Angular Study Notes - II

Angular Binding

previous

This post is the notes of Official Angular Document. This amazing document can be found here.

1. Binding Syntax: an Overview

Data-binding is a mechanism for corrdinating what users see, specifically with app data values. Angular provides many kinds of data-binding. Binding types can be grouped into three categories distinguished by the direction of data flow:

  • From the soure-to-view
  • From the view-to-source
  • Two-way sequence: view-to-source-to-view
Type Syntax Category
Interpolation
Property
Attribute
Class
Style
\{\{expresion}}
[target]="expression"
bind-target="expression"
One-way from data source
to view target
Event (target)="statement"
on-target="statement"
One-way from view target
to data source
Two-way [(target)]="expression"
bindon-target="expression"
Two-way
  • Binding types other than interpolation have a target name to the left of =, either surrounded by punctuation, [], (), or preceded by a prefix: bind-, on-, bindon-.
  • The target of a binding is the property or event inside the binding punctuation: [], (), [()]

2. Data-binding and HTML

With data-binding, you can control things like the state of a button:

<!-- Bind button disabled state to `isUnchanged` property -->
<button [disabled]="isUnchanged">Save</button>

Notice that the binding is to the disabled property of the button’s DOM element, not the attribute. This applies to data-binding in general. Data-binding works with properties of DOM elements, components, and directives, not HTML attributes.

3. HTML attribute vs. DOM property

The distinction between an HTML attribute and a DOM property is key to understanding hwo Angular binding works. Attributes are defined by HTML. Properties are accessed from DOM, or the Document Object Model, nodes. When the browser loads the page, it “reads” the HTML and generates DOM objects from it. For element nodes, most standard HTML attributes automatically become properties of DOM objects. But,

  • A few HTML attributes have 1:1 mapping to properties; for example, id.
  • Some HTML attributes don’t have corresponding properties; for example, aria-*.
  • Some DOM properties don’t have corresponding attributes; for example, textContent.

This general rule can help you build a mental model of attributes and DOM properties: attributes initialize DOM properties and then they are done. Property values can change; attribute values can’t.
The HTML attribute and the DOM property are not the same thing, even when they have the same name.

DOM properties

DOM nodes are regular JS objects. Properties are what’s in DOM objects. We can alter them. They can have any value. They are case-sensitive(e.g. elem.nodeType, not elem.NoDeType). DOM property values are not always strings. They can be boolean.

HTML attributes

In HTML, tags may have attributes. When the browser parses the HTML to create DOM objects for tags, it recognizes standard attributes and creates DOM properties from them. So attributes are what’s written in HTML. And HTML attributes have the following features:

  • Their name is case-insensitive
  • Their values are always strings.

Example 1: <input>

When the browser renders <input>, it creates a corresponding DOM node with a value property initialized to “Sarah”.

<input type="text" value="Sarah">

When the user enters “Sally” into the input, the DOM element value property becomes “Sally”. However, if you look at the HTML attributes value using input .getAttribute('value'), you can see that the attribute remains unchanged - it returns “Sarah”.

The HTML attribute value specifies the initial value; the DOM value property is the current value.

Example 2: <button>

The disable property of a button is false by default so the button is enabled. When adding the disable attribute, its presence alone initializes the button’s disable property to true so teh button is disabled.

<button disable>Test Button</button>

Adding and removing the disabled attribute disables and enables the button. However, the value of the attribute is irrelevant, which is why you cannot enable a button by writing <button disabled="false">Still Disabled</button>

To control the state of the button, set the disabled property,

Note: Though you could technically set the [attr.disabled] attribute binding, the values are different in that the property binding requires to a boolean value, while its corresponding attribute binding relies on whether the value is null or not. That is,

<input [disabled]="condition ? true : false">
<input [attr.disabled]="condition ? 'disabled' : null">

Generally, use property binding over attribute binding as it is more intuitive (being a boolean value), has a shorter syntax, and is more performant.

Template binding works with properties and events, not attributes.

In Angular, the only role of attributes is to initialize element and directive state. When you write a data-binding, you’re dealing exclusively with properties and events of the target object.

4. Binding targets

The target of a data-binding is something in the DOM. Depending on the binding type, the target can be a property (element, component, or directive), an event (element, component or directive), or sometimes an attribute name. They can be summarized as

Type Target Examples
Property Element property
Component property
Directive property
src, hero and ngClass in the following:
<img [src]="heroImageUrl">
<app-hero-detail [hero]="currentHero"> </app-hero-detail>
<div [ngClass]="{'special': isSpecial}">
Event Element event
Component event
Directive event
click, deleteRequest, and myClick in the following:
<button (click)="onSave()">Save</button>
<app-hero-detail (deleteRequest)="deleteHero()"></app-hero-detail>
<div (myClick)="clicked=$event" clickable>click me</div>
Two-way Event and property <input [(ngModel)]="name">
Attribute Attribute
(the exception)
<button [attr.aria-label]="help">help</button>
Class class property <div [class.special]="isSpecial">Special</div>
Style style property <button [style.color]="isSpecial ? 'red' : 'green'">

5. Property Binding [property]

Use property binding to set properties of target elements or directive @Input decorators.

One-way in

  • Property binding flows a value in one direction, from a component’s property into a target element property.
  • Cannot use property binding to read or pull values out of target elements.
  • Cannot use property binding to call a method on the target element. If the element raises events, you can listen to them with an event binding.

Examples:

  • <img [scr]="itemImageUrl">: set an element property to a component property value.
  • <td [colSpan]="2">Span 2 columns</tr>: bind to the colSpan property. Notice that it’s not colspan, which is the attribute.
  • <button [disable]="isUnchanged">Disable Button</button>: Bind button disabled state to isUnchanged property.
  • <p [ngClass]="classes">[ngClass] binding to the classes property making this blue</p>: set a property of directive, [ngClass] binding to the classes property making this….
  • <app-item-detail [childItem]="parentItem"></app-item-detail>: set the model property of a custom component - a great way for parent and child components to communicate.

Binding target

An element property between [] identifies the target property. There is also the bind- prefix alternative. That is
<img [src]="itemImageUrl"> is equivalent to <img bind-src="itemImageUrl">.

Though the target name is usually the name of a property, there is an automatic attribute-to-property mapping in Angular for several common attributes. These include class/className, innerHtml/innerHTML, and tabindex/tabIndex.

Avoid side effects

Return the proper type

The template expression should evaluate to the type of value that the target property expects. For exampe, ListItemComponent is nested within AppComponnet and the item property expects an object.

In src/app/app.component.html

<app-list-item [items]="currentItem"></app-list-item>

In src/app/list-item.component.ts

@Input() items: Item[];

In scr/app/item.ts

export class Item {
    id: number;
    name: string;
}

So in src/app/app.component.ts, we give value to the current Item as follows

currentItem = [{
	id: 49, 
	name: 'phone'
}];

Remember the brackets []

If you omit the brackets, Angular treats the string as a constant and initiazlize the target property with that string. E.g.

<app-item-detail childItem="parentItem"></app-item-detail>

Omitting the [] will render the string parentItem not the value of parentItem.

One-time string initialization

You should omit the [] when all of the follwoing are tre:

  • The target property accepts a string value.
  • The string is a fixed value that you can put directly into the template.
  • This initial value never changes.

Property binding vs. interpolation

You often have a choice between interpolation and property binding. The following binding pairs do the same thing:

<p><img scr=""> is the <i>interpolated</i> image.</p>
<p><img [src]="itemImageUrl"> is the <i>property bound</i> image.</p>

<p><span>"" is the <i>interpolated</i> title.</span></p>
<p><span [innerHTML]="propertyTitle"></span> is the <i>property bound</i> title.</p>

Interpolation is a convenient alternative to property binding in many cases. When rendering data values as strings, there is no technical reason to prefer one form to the other. However, when setting an element property to a non-string data value, you must use property binding.

Content security

For example, in src/app/app.componnet.ts

evilTitle = 'Template <script>alert("evil never sleeps)</script> Syntax';

Both interpolation and property binding will render the content harmlessly.

6. Attribute, class, and style bindings

Attribute binding

Usually, setting an element property with a property binding is preferable to setting the attribute with a string. However, sometimes there is no element property to bind, so attribute binding is the solution. Attribute binding syntax: between the [], start with the prefix attr, followed by a dot (.), and the name of the attribute. E.g.

<!-- create and set an aria attribute for assistive technology -->
<button [attr.aria-label]="actionName"> with Aria</button>

Class binding

Add and removes CSS class names from an element’s class attritube with a class binding. Syntax: between the [], start with the prefix class, optionally followed by a dot (.) and the name of a CSS class: [class.class-name]. For example, we can bind to a specific class name. Angular adds the class when the template expression evaluates to truthy. It removes the class when the expressio is falsy.

<h3>toggle the "special" class on/off with a property:</h3>
<div [class.special]="isSpecial">This div is special</div>

<h3>binding to class.special overrides the class attribute:</h3>
<div class="special" [class.special]="!isSPecial">This one is not so special.</div>

<h3>Using the bind- syntax:</h3>
<div bind-class.special="special">This class binding is special too.</div>

Style binding

You can set inline styles with a style binding.
Syntax: [style.style-property]. E.g.

<button [style.color]="isSpecial ? 'red' : 'green'">Red</button>

Some style binding styles have a unit extension. The following example conditionally sets the font size in em and %units. E.g.

<button [style.font-size.em]="isSpecial ? 3 : 1">Big</button>
<button [style.font-size.%]="isSpecial ? 150 : 50">Small</button>

This technique is suitable for setting a single style, but consider the NgStyle directive when setting several inline styles at the same time.

7. Event binding (event)

Event binding allows you to listen for certain events such as keystrokes, mouse movements, clicks, and touches.
Syntax: (event)="action()", event is the target event name and action() is teh template statement; alternatively, we can use on- prefix, i.e. on-click="action()"

$event and event handling statements

In an event binding, Angular sets up an event handler for the target event. When the event is raised, the handler executes the template statement. The template statement typically involves a receiver, which performs an action in response to the event, such as storing a value from the HTML control into a model.

The binding conveys information about the event. This information can include data values such as an event object, string, or number named $event. The target event determines the shape of the $event object. If the target event is a native DOM element event, then $event is a DOM event object, with properties such as target and target.value. For example,

<input [value]="currentItem.name"
       (input)="current.name=$event.target.value">

This code binds property and event seperately.

  • [value]: property binding
  • (input): event binding. To update the name property, the changed text is retrieved by $event.target.value.

Custom events with EventEmitter

Directives typically raise custom events with an Angular EventEmitter. The directive creates an EventEmitter and exposes it as a property. The directive calls EventEmitter.emit(payload) to fire an event, passing in a message payload, which can be anything. Parent directives listen for the event by binding to this property and accessing the payload through the $event object. For example,

In src/app/item-detail/item-detail.component.html we bind an click event:

<img src="" [style.display]="displayNone">
<span [style.text-decoration]="lineThrough"></span>
<button (click)="delete()">Delete</button>

In src/app/item-detail/item-detail.component.ts:

// This component makes a request but it can't actually delete a hero.
@Output() deleteRequest = new EventEmitter<Item>();

delete() {
  this.deleteRequest.emit(this.item);
  this.displayNone = this.displayNone ? '' : 'none';
  this.lineThrough = this.lineThrough ? '' : 'line-through';
}

The component defines a deleteRequest property that returns an EventEmitter. When the user clicks delete, the component invokes the delete() method, telling the EventEmitter to emit an Item object.

In src/app/app.component.html

<app-item-detail 
    (deleteRequest)="deleteItem($event)" 
    [item]="currentItem">
</app-item-detail>

In src/app/app.component.ts, we can do the customized events by editting deleteItem(item: Item):

deleteItem(item: Item) {
	// do something;
}

Template statements have side effects

Though template expressions shouldn’t have side effects, template statements usually do. The deleteItem() method does have a side effect: it deletes an item.

8. Two-way binding [(…)]

Two-way binding gives your app a way to share data between a component class and its template.

Basics of two-way binding

Two-way binding does two things:

  • Sets a specific element property.
  • Listens for an element change event.
    Angular offers a special two-way data binding syntax for this purpose, [()]. The [()] syntax combines the brackets of property binding, [], with the parentheses of event binding, (). Visually, [()] = BANANA IN A BOX.

Two-way binding in forms

The two-way binding syntax is a great convenience compared to separate property and event bindings. It would be convenient to use two-way binding with HTML form elements like <input> and <select>. However, no native HTML element follows the x value and xChange event pattern.

next

   Reprint policy


《Angular Study Notes - II》 by Tong Shi is licensed under a Creative Commons Attribution 4.0 International License
 Previous
Rectangle Area Rectangle Area
LeetCode Q 223 - Rectangle AreaFind the total area covered by two rectilinear rectangles in a 2D plane. Example: Input:
2019-06-21 Tong Shi
Next 
Angular Study Notes - I Angular Study Notes - I
Angular TemplateThis post is the notes of Official Angular Document. This amazing document can be found here. The Angula
2019-06-20 Tong Shi
  TOC