Tuesday, August 13, 2019

Data binding in Angular

There are several ways to handle data binding in Angular framework:

1. string interpolation
Using {{ }} to include a component property or expression in html markup, Angular will convert the property into a string, and show it in the html page. Note string interpolation only works in normal html text, not in element attribute.
<p>The sum of 1 + 1 is not {{myProperty}}.</p>

2. element property binding
Using [] with an html element attribute name to dynamically binding the html element attribute to a component's property, so that the value is come from the component's property at runtime. For example, in the below example, the image src is set to Angular component's itemImageUrl property's value.

<img [src]="itemImageUrl2"> 

Comparing to this, if the html attribute is not surrounded by [], then it means the attribute value is set to the hardcoded value of the string. For example
<img src="https://www.gstatic.com/webp/gallery3/1.png">    

Angular can recognize [] in the element attribute, so then handle anything included in "" as typescript code.


3. element event binding
Using () to include a html element event name, and set it to value to a method call in quotation mark.
 <button (click)="onButtonClicked()">Delete</button>
If the event takes any event parameter, add $event as parameter in calling method.

4. two way binding with ngModel
NgModel directive attribute depends on FormsModule for Angular template based form handling.

when nModel is used for a standalone control, it allows one way (using [] syntax) or two way binding ([()] syntax) for html input element  Only input element types (Input, select, textarea) or custom element implemented ControlValueAccessor interface can use ngModel for two way binding, as the property is binding to the html element's value property as default.
In addition to binding to ts property, [(ngModel)] can also bind to item or item's property got from ngFor loop.

To use two way binding, must import FormsModule in the app module as below.

import { FormsModule } from '@angular/forms';

imports: [
BrowserModule,
FormsModule
],

Html template file:
<input [(ngModel)]="myname" id="example-ngModel">
Web component ts file:
export class FormComponent implements OnInit {
  myname= 'default name';

Note, when using ngModel for html element inside a form, it requires a name attribute, and ngForm will synchronize the html element with component class, so there is no need to setup oneway or two way binding.

If local reference variable is not assigned to value of 'ngModel', then when passing the local variable as a method parameter to ts code, the type of parameter in ts code is HtmlInputElement. If the local reference variable is assigned to the value of 'ngModel', then the type of the parameter in ts code is NgModel
  <div><input type="text" #local1></div>
  <div><input type="text" ngModel #local2="ngModel"></div>
  <ion-button (click)="onCreateOffer(local1, local2)">

ts code:
  onCreateOffer(l1: HTMLInputElement, l2: NgModel) {
    console.log("create offer place", typeof(l1), typeof(l2) );
  }

5. style binding
A element's style can  bind to a property or method's return value as shown below
<p [ngStyle]="{backgroundColor: getColor()}">servers works!</p>

In component typescript file, getColor method is defined as
getColor() {
return this._color;


6. Conditional style class binding
A element's style class can bind to a class conditionally based on property or method return value as shown below. If getColor() returns 'red', then the online style class will be applied to the button element.
<button [ngClass]="{online:getColor()=='red'}" [disabled]="!allowNewServer" class="btn btn-primary" (click)="onCreateServer()">my button</button>

The style class is defined as 
@Component({
selector: 'app-servers',
templateUrl: './servers.component.html',
styles: [`
.online {
color: pink;
}`]
})


7. local reference passed as template html method parameter
In html template, local reference variable can be used to pass the html element or Angular web component as parameter to method call. The below sample pass html input type and SecondComponent as parameter to a js method.

Note, template reference variable are only visible within the template definition scope, as ngIf, ngFor will create a separate template block, so template reference variables defined within ngIf or ngFor clause are not visible to js code outside of the ngIf or ngFor clause. In this case, ViewChild can be used as an alternative solution.

When reference input element

app component html template:
<input type="text" #local1>
<app-second #local2></app-second>
<button class="btn btn-primary" (click)="onMyClick(local1, local2)">button</button>

app Component typescript:
export class AppComponent {
title = 'local';


onMyClick(l1, l2) {
console.log('on click called');
console.log(l1.value);
console.log(l2.getSecondValue()); //getSecondValue is a method in SecondComponent angular web component
}
}


Second Component typescript:

export class SecondComponent implements OnInit {
constructor() { }
ngOnInit() {
}

getSecondValue(){
return 'value from second component';
}
}

8. @ChildView  
@ChildView can let typescript code directly reference the web components.

@ChildView method parameter must indicate which html element is associated with the typescript variable. The below are two types can be specified by @ViewChild query parameter

Html element: 
Single quotation mark is used around the local reference name when specifying a viewChild variable.

app component html file
<input type="text" class="form-control" #local1>
<app-second #local2></app-second>
<button class="btn btn-primary" (click)="onMyClick(local1, local2)">button</button>
<button class="btn btn-primary" (click)="onClick()">button2</button>

Web component typescript file
export class AppComponent {
@ViewChild('local1', {static: true}) local1;
@ViewChild('local2', {static: true}) local2;

onClick(){
console.log(this.local1 + ', ' + this.local1.nativeElement.value);
console.log(this.local2 + ', ' + this.local2.getSecondValue());
}
}

8.2 web component class name
html file
<input type="text" class="form-control" >
<app-second ></app-second>
<button class="btn btn-primary" (click)="onMyClick(local1, local2)">button</button>
<button class="btn btn-primary" (click)="onClick()">button2</button>

web component file
@ViewChild(SecondComponent, {static: true}) local2;


onClick(){
console.log(this.local2 + ', ' + this.local2.getSecondValue());
}




1 comment: