Angular Study Notes - III

Angular Binding

previous

This 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 importslist.

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. When NgIf 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 #.


   Reprint policy


《Angular Study Notes - III》 by Tong Shi is licensed under a Creative Commons Attribution 4.0 International License
  TOC