A markup language (like HTML) is better suited for building a view. It is declarative and easy to read. As we build web pages in an Angular application, views are built with HTML. Data and logic stay in the TypeScript classes. Traditionally, the JavaScript API (and JQuery) allows you to query and select an HTML element. The JavaScript code might read the value from the selected element or set a value to it. This becomes error prone and convoluted as the application grows in size and complexity.
Angular solves this problem with data binding. Data binding helps bring data in TypeScript code to the view or HTML, and vice versa. This chapter discusses data binding and its approaches. This chapter also covers Angular’s change detection strategy. It is a key Angular feature for data binding. Angular’s new approach (compared to the AngularJS 1.x digest cycle) is at the heart of better-performing modern Angular applications.
Let’s begin with data binding.
Interpolation
Data Binding: Interpolation
The context of data binding is the TypeScript class component. That is, variables and functions are class-level properties and methods on the component (see the variable “name” and the getFirstAppearance() function in Listing 5-1). It is possible that the values of these variables change on the fly. Data binding automatically updates the value of the view in DOM.
Note
We can override the default interpolation delimiter ( {{ }} ) with a different string value by using the interpolation field on a component decorator.
Property Binding
Property Binding
TypeScript Class Component with Fields
You can dynamically change the values of these fields. It enables the drop-down on the fly, changes the image, and sets a new value to the text field.
Alternate Syntax for Property Binding
Property Binding with bind-property Name
Note
The “bind-” syntax is not often used. Enclosing a property in square brackets is a popular approach. The alternate syntax is described for information only.
Notice that the direction of data binding is one way. It goes from the component class to the HTML template. As values change in the component, the view is updated. Various events, such as server-side API calls and DOM (Document Object Model) events could cause the values to change. Data binding ensures updating the view.
With property binding, the binding target is an element’s DOM properties; not the HTML elements’ attributes. Please note that the DOM’s objects are different from HTML elements. The latter are created in the HTML web page when it loads. DOM properties are initialized by the HTML elements and attributes. The DOM element properties can change while using the web page.
In many cases, attribute names match property names, but there are exceptions, and Angular property bindings depend on DOM properties.
Incorrect Usage of an Attribute in Property Binding
Property Binding with colSpan Property Name
Attribute Binding
Class Binding (CSS classes)
Class binding allows you to apply a CSS class on an element on the fly. Typically, CSS classes define the various style aspects of an element, including the font, foreground/background colors, border styles, and so forth.
Use data binding to apply one or more CSS classes on an element. It also provides the ability to change the CSS class, and hence, change the styles of an element.
Class Binding Sample
Class with CSS String on a Variable
We could add more CSS classes or remove an existing CSS class from this string. This would change the look and feel of the element.
Boolean Variables that Control to Show or Hide a CSS Class on an Element
Bind Boolean Variables with Class Binding
ngClass Directive
An Object Encapsulating CSS Classes for Data Binding
Note the data type for the cssClasses variable, {[key: string]: Boolean}. Let’s decode the anonymous TypeScript type defined in this sample. On the outset, it is an object with key/value pairs. The key is a string. The values in Listing 5-13 (show-border, show-bg-color, etc.) use a hyphen in the key name. A typical JSON object does not use a hyphen in the key name or field name. Considering that we are defining a CSS class, it is a general practice to use a hyphen in CSS class names.
We toggle each key (which is nothing but the CSS class name) as true or false. The values can change on the fly. With the data binding applied by the directive, the CSS class is reflected in the view.
Note
A directive in Angular enables adding a custom behavior to the HTML markup and elements. I discuss directives in an upcoming chapter.
Template Using the ngClass
Style Binding
Style Binding
Styles Values Defined in the Component
Note
font-size is followed by a unit as well. In Listing 5-15, it is pt (points). You can use other measurements, like % or px.
ngStyle Directive
Style Object For Inline Styles
ngStyle Directive for Inline Styles
Event Binding
When a user changes the values of a text field, clicks a button, or submits a form, TypeScript code needs to capture the user’s actions and data input. Event binding is used for this. Each action, key stroke, and button click generates events. The direction of the binding is from the view or the HTML template to the TypeScript file component. It goes in the opposite direction of property bindings.
We bind events on an element with a function in the TypeScript file component. The context of the binding remains in the TypeScript class component (like property binding).
Angular captures the event emitted by the element and creates an $event object. Since there are many types of events, raised by various controls, the structure of an $event object differs. Depending on the event, we can capture the necessary information from the object.
Input Event and Handler
Note
For binding, an event can be enclosed in braces or prefixed with on-eventName. (click)=”handlerName()” is the same as on-click=”handlerName”.
The first statement prints the complete event object.
The second statement prints the event type information, which is different for the various types of events that HTML elements can generate.
The third statement prints the value of the element, which is useful for input controls like text fields, drop-downs, and so forth. On the other hand, elements like buttons do not change values often.
We access the value by using the value field in the target object. The target is on the event object raised by the element.
The event type is “input” and the value is the data keyed into the text field.
Drop-down with Change Event
Button with Click Event
Typically, the event type is “click” and the value of the button is not significant.
The event handler in this example is for demonstration purposes. A typical handler might update the model object associated with the component. The model object may eventually be sent to a server API for insert or update operations in a database.
Property binding and interpolation provide values to the view (HTML template) from the model object (component fields).
Event binding captures user input in the view or HTML template. It provides values to the model object (component fields) from the view (HTML template).
So far, data binding has been one way—either toward the view from the model object or toward the model object from the view.
Combine Property Binding and Event Binding
Two-Way Data Binding
Two-way data binding simplifies updating model objects as the user changes the view; and updating the view as model objects change; hence, it is called two-way.
- 1.
Import the forms module.
We have been building superhero components as part of the superheros Material Design module. Import the forms module in it, so that we can use ngModel for two-way data binding. Make the changes shown in Listing 5-22 in superheroes-material-design.module.ts.
Notice that we imported FormsModule from @angular/forms. Next, we added it to the imports array on the @NgModule decorator of the TypeScript class.
Import Forms Module for ngModel
- 2.Use ngModel in the component for two-way data binding. As described in the prevoius section, two-way data binding is about combining
- a.
Property binding, which is used with syntax enclosing the variable in square brackets and
- b.
Event binding, which is used with syntax enclosing the variable in round brackets.
- a.
The ngModel directive enables you to combine the two with the directive name in the middle: [(ngModel)]. It is colloquially referred to as banana in a box.
ngModel for Two-Way Data Binding on a Text Field
Show the ngModel value with Interpolation or Property Binding
The ngModel directive internally raises an ngModelChange event every time there is a change to the text field. The event sets a value on the model object. Angular adds the directive in the input elements.
Change Detection
So far, you have seen data binding and its approaches. You know that Angular updates the view from the model and vice versa. A model refers to a field or an object in the TypeScript class component. A model is an object representation (of data) for the view.
User interactions: : Edit the fields and perform actions using controls such as buttons, swipes, and so forth.
Ajax calls : XHR and fetch calls that retrieve data from a remote server using RESTful API calls.
JavaScript API : Timeouts, like setTimeout and setInterval.
The change detection process identifies a change and synchronizes the view and model.
Angular uses Zone.js in the change detection process. It is a JavaScript library included with Angular. It provides the execution context for change detection. Facilitated by Zone.js, Angular taps into the browser API to identify a change. As the user interacts with the view, or an Ajax call returns data, the change detection occurs for each component.
Angular creates a change detector for each component. The change detector is not generic for the whole application, but rather created specifically for each component, which makes the change detection process faster. The change detector identifies changes to the template expression and updates the view and model objects. Figure 5-9 depicts a separate change detector in each component.
Angular emphasizes a unidirectional data flow from the parent to the child components through input attributes. When a change is detected, it is propagated to all child components, which is further sent down to the other nodes.
Detecting change is a simple process of comparing a component’s previous input with the new input. If a change is identified, in the complete tree under the component, verify and synchronize the template expressions with the model.
Change Detection Strategy
A change detection strategy is applied at the component level. We can specify the strategy as part of a component decorator. It affects the component and its children. Angular provides two change detection strategies: the default and OnPush.
A change could be caused by user interaction, such as the click of a button or API calls. The change is propagated from parent to child components. Often change is identified with an input parameter value change.
Default Change Detection Strategy
Input Attributes on SuperheroProfile Component
Class Fields That Are Input Attributes to the Superhero Profile Component
As mentioned, a separate change detector is generated for each component. When an event that can cause change is raised, it compares input attributes, the previous value, and the new value. If there is a difference, the change is identified and the component template is updated.
For the SuperheroProfile component, each of the input attribute values— superpowers, address, name, firstAppearance, and lives-in—are compared.
With the default change detection strategy, for example, name and firstAppeared is compared between previous and new value. The value types are a string and a number, respectively. If there is a value change, a simple === comparison identifies the change; however, it is different with reference types, for example, an address. If we update the address object, the equals (===) comparison will fail. The reference comparison checks the memory address of the object. We updated the same object, and hence, no change is identified. Here, the address is a mutable type object.
Note
There are also immutable type objects that do not change their value. We need to create a new object at a different memory location to update a value of these types.
Hence, Angular has to compare all the fields in the object. In a default change detection strategy, that’s exactly what is done by a component-specific change detector; however, it compares fields if they are part of the template in the superhero profile component. In the previous example, the address field, the city field, and the firstLine variable values are compared.
When the user changes the value in the AppComponent’s text field, the new values are propagated to the SuperheroProfile component.
This approach is costly because the code has to compare child objects and fields, but it is effective in identifying the change.
Note
Overall, the Angular’s component-specific change detector is efficient and fast compared to the AngularJS 1.x digest cycle performance.
Default Change Detection Strategy
OnPush Change Detection Strategy
OnPush compares values by reference. It does not compare individual fields on reference types; hence, it is faster than the default approach.
In Listing 5-28, the address object is compared by reference. The two address fields (firstLine and city) are not compared, even though they are part of the template in the SuperheroProfile component.
If the OnPush strategy is used (for better performance), we need to use immutable objects. As mentioned, immutable objects can never be mutated or updated. A new instance is created every time there is a change. As a consequence, a new instance has a new memory location. This ensures that the reference comparison identifies the change, and it is done faster because individual fields do not need to be compared.
OnPush Change Detection Strategy
Conclusion
This chapter covered Angular’s data binding and change detection features. It began with an explanation of data binding and how it eases web application development.
Interpolation and property binding help show the values of TypeScript component fields in the template. It works toward the template or view, away from the model.
Event binding allows changes made by the user to reflect in model objects. The latter are defined in TypeScript component classes. These are the fields and objects defined with the component.
CSS class binding and style binding combine the power of data binding with web page style features.
Change detection is crucial for performant and fluid web UI applications. Two strategies of change detection were discussed: default and on-push.
Exercise
Dinosaur name
Description
Family drop-down menu: the values are Herrerasauridae, Ceratopsidae, Tyrannosauridae, and Plateosauridae
Submit button
The user should see the dinosaur information in a separate section of the page. The section could be to the side of or below the form. Use interpolation to show the dinosaur values in this section.
Use ngModel and two-way data binding to persist the form’s values in a model object.
When the Submit button is clicked, the console logs the values provided by the user.
References
Angular documentation on templates and data binding (https://angular.io/guide/template-syntax#template-syntax)
Angular University blog on change detection (https://blog.angular-university.io/how-does-angular-2-change-detection-really-work/)