Angular Binding
previousThis post is the notes of Official Angular Document. This amazing document can be found here.
1. Built-in directives
Angular offers two kinds of build-in directives: attribute directives (NgClass
, NgStyle
, [(ngModel)]
) and structural directives (NgIf
, NgFor
).
1.1 Built-in attribute directives
The most common attribute directives are as follows:
NgClass
- adds and removes a set of CSS classes.NgStyle
- adds and removes a set of HTML styles.NgModel
= adds two-way data binding to an HTML form element.
NgClass
<!-- toggle the "sepcial" class on/off with a proerty -->
<div [ngClass]="isSpecial ? 'sepcial' : ''">This div is special</div>
To add or remove a single class, use class binding rather than NgClass. That is,
<!-- use class binding -->
<div [class.special]="isSpecial">This div is special</div>
NgStyle
User NgStyle
to set many inline styles simultaneously and dynamically, based on the state of the component.
Previously, we know we can set a single sytle via style binding. For example,
<div [style.font_size]="isSpecial ? 'x-large' : 'small'">This dive is x-large or smaller.</div>
With NgStyle
, we can set many inline styles at the sane time. For example,
<div [ngStyle]="currentStyles">This div is initially italic, normal weight, and extra large (24px).</div>
currentStyles
is set in **.component.ts
currentStyles: {};
setCurrentStyles() {
// CSS styles: set per current state of component properties
this.currentStyles = {
'font-style': this.canSave ? 'italic' : 'normal',
'font-weight': !this.isUnchanged ? 'bold' : 'normal',
'font-size': this.isSpecial ? '24px' : '12px'
};
}
Remember to call setCurrentStyles(), both initially and when the dependent properties change.
[(ngModel)]: Two-way binding
The NgModel
directives allows you to display a data property and update that property when the user makes changes. For example,
<label for="example-ngModel">[(ngModel)]:</label>
<input [(ngModel)]="currentItem.name" id="example-ngModel">
Import FormsModule
to use ngModel
. Before using the ngModel
directive in a two-way data binding, you must import the FormsModule
and add it to the NgModule
‘s imports
list.
Seperate ngModel
bindings are an improvemnt over binding to the element’s native properties. Its syntax is: [ngModel]="***" (ngModelChange)="***"
.ngModel
data property sets the element’s value property and the ngModelChange
event property listens for the changes to the element’s value.
The [(ngModel)]
can only set a data-bound property. If we need to do something more, we can write the expanded form. For example, we want to change the <input>
value to uppercase:
<input [ngModel]="currentItem.name" (ngModelChange)="setUppercaseName($event)" id="example-uppercase">
1.2 Built-in structural directives
Structural directives are responsible for HTML layout. They shape or reshape the DOM’s structure, typically by adding, removing, and manipulating the host elements to which they are attached. Common build-in structural directives include NgIf
, NgFor
and NgSwitch
.
NgIf
You can add or remove an element from the DOM by applying an NgIf
directive to a host element. Bind the directive to a condition expression.
<app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>
When the isActive
expression returns a truthy value, NgIf
adds the ItemDetailComponent
to the DOM. When the expression is falsy, NgIf
removes the ItemDetailComponent
from the DOM, destroying that component and all of its sub-components.
Show/hide vs NgIf
<!-- isSpecial is true -->
<div [class.hidden]="!isSpecial">Show with class</div>
<div [class.hidden]="isSpecial">Hide with class</div>
- When you hide an element, the element and all of its descendants remain in the DOM. All components for those elements stay in memory and Angular may continue to check for changes.
NgIf
works differently. WhenNgIf
is false, Angular removes the element and its descendants from the DOM. It destroys their components, freeing up resources, which results in a better user experience.- If you are hiding large component trees, consider
NgIf
as a more efficient alternative to showing/hiding.
Show/hide vs NgIf
Another advantage of ngIf
is that you can use it to guard against null. Show/hide is best suited for very simple use cases, so when you need a guard, opt instead for ngIf
. Angular will throw an error if a nested expression tries to access a property of null.
The following shows NgIf
guarding two <div>
s. The currentCustomer name appears only when there is a currentCustomer. The nullCustomer will not be displayed as long as it is null.
<div *ngIf="currentCustomer">Hello, </div>
<div *ngIf="nullCustomer">Hello, </div>
NgFor
NgFor
is a repeater directive—a way to present a list of items. You define a block of HTML that defines how a single item should be displayed and then you tell Angular to use that block as a template for rendering each item in the list.
For example,
<div *ngFor="let item of items"></div>
ngFor
can also be applied to a component element,
<app-item-detail *ngFor="let item of items" [item]="item"></app-item-detail>
What does let item of items
mean? Take each item in the items array, store it in the local item looping variable, and make it available to the templated HTML for each iteration.
*ngFor
with index
The index property of the NgFor
directive context returns the zero-based index of the item in each iteration. You can capture the index in a template input variable and use it in the template. For example,
<div *ngFor="let item of items; let i = index">NaN-</div>
*ngFor
with trackBy
Make your code more efficient for large lists.
trackByItems(index: number, item: item) {return item.id}
<div *ngFor="let item of items; trackBy: trackByItems">
()
</div>
NgSwitch
2. Template reference variables (#var)
A template reference variable is often a reference to a DOM element within a template. It can also refer to a director (which contains a component), an element, TemplateRef, or a web component.
- First, use the hash symbol (#) to declare a reference variable.
- Then, we can refer to a template reference variable anywhere in the component’s template.
<input #phone placeholder="phone number" />
<!-- #phone declares a phone variable on <input> element -->
<!-- phone refers to the input element; pass its value to an event handler -->
<button (click)="callPhone(phone.value)">Call</button>
How a reference variable gets its value
In most cases, Angular sets the reference variable’s value to the element on which it is declared. In the previous example, phone
refers to the phone number <input>
. The button’s click handler passes the <input>
value to the component’s callPhone()
method.
The NgForm
directive can change that behavior and set the value to something else.
<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">
<label for="name">Name <input class="form-control" name="name" ngModel required/>
</label>
<button type="submit">Submit</button>
</form>
<div [hidden]="!itemForm.form.valid">
<p></p>
</div>
With NgForm
, itemForm
is a reference to the NgForm
directive with the ability to track the value and validaty of every control in the form.
The native <form>
element doesn’t have a form property, but the NgForm
directive does, which allows disabling the submit button if the itemForm.form.valid
is invalid and passing the entire form control tree to the parent component’s onSubmit()
method.
Template reference variable consideration
A template reference variable (#phone
) is not the same as a template input variable (let phone
) such as in an *ngFor
. The scope of a reference variable is the entire template. So, don’t define the same variable name more than once in the same template as the runtime value will be unpredictable.
Alternative syntax
We can use ref-
prefix alternative to #
.