liveBook · Manning

Two-way binding

As explained in Pro Angular 16

Two-way data binding is a technique that synchronizes changes between application data and its user-interface representation in both directions.

Two-way binding keeps an HTML element and application data synchronized. A one-way binding displays a component value; an event binding carries user changes back to the component. Combining both lets either side change the other. It is especially useful for form controls. section 11.2 section 13.3

Marking a task complete

A checkbox bound with `[(ngModel)]="item.complete"` displays a task’s completion state and updates that property when toggled. Other bindings that depend on the property update too, including the displayed true/false value and the count of incomplete tasks. A separate toggle can bind to `showComplete` to control whether completed tasks appear. section 2.6 section 2.9

The two directions can be written separately. For an input tied to a `selectedProduct` signal, `(input)` sets the signal from the element’s value, while `[value]` reads the signal into the element. Two inputs using that pair stay synchronized; editing either also updates dependent interpolation and a highlighted table row. section 13.3

The `ngModel` directive replaces that repeated pair on form elements. Write `[(ngModel)]="property"`: the round brackets inside square brackets are nicknamed “banana-in-a-box.” Import `FormsModule` to make the form feature available. Check the brackets if a binding does not behave as expected. section 13.3.1 section 13.0

Entering a product

Bind three inputs to `newProduct.name`, `newProduct.category`, and `newProduct.price` with `[(ngModel)]`. A JSON display makes changes to the object visible while the user types. A separate click binding passes `newProduct` to the Create action; two-way binding handles synchronization, not the button action. section 13.4.1

In Angular 16, `ngModel` does not bind directly to signals. A getter and setter can expose a simple signal value as a regular property, but that approach is awkward for many bindings. For forms that update properties of a data object, use conventional component properties in this setup. section 13.3.1 section 13.4.1

A custom directive can offer the same syntax. An input named `paModel` receives application changes; an output named `paModelChange` emits user changes. Angular’s matching names let `[(paModel)]="newProduct.name"` replace the separate property and event bindings. This example supports input elements rather than the range of controls supported by `ngModel`. section 14.6

Listing 14.19. The contents of the twoway.directive.ts file in the src/app folder
import {
    Input, Output, EventEmitter, Directive,
    HostBinding, HostListener, SimpleChange
} from "@angular/core";
 
@Directive({
    selector: "input[paModel]"
})
export class PaModel {
 
    @Input("paModel")
    modelProperty: string | undefined = "";
 
    @HostBinding("value")
    fieldValue: string = "";
 
    ngOnChanges(changes: { [property: string]: SimpleChange }) {
        let change = changes["modelProperty"];
        if (change.currentValue != this.fieldValue) {
            this.fieldValue = changes["modelProperty"].currentValue || "";
        }
    }
 
    @Output("paModelChange")
    update = new EventEmitter<string>();
 
    @HostListener("input", ["$event.target.value"])
    updateValue(newValue: string) {
        this.fieldValue = newValue;
        this.update.emit(newValue);
    }
}

The directive listing shows the two directions: `ngOnChanges` updates the host input’s value, and an `input` listener emits the new value through `paModelChange`. section 14.6

How Pro Angular 16 covers it

How deep it goes
Works through paired bindings, ngModel setup, a form, and a custom directive; limits the custom implementation to input elements.
Examples
Uses task checkboxes, synchronized product-name inputs, a product-entry form, and a custom input directive.
What it assumes
Assumes HTML elements and component properties; explains binding direction and demonstrates event/property binding pairs before the ngModel shortcut.
What you can do after
Build it from scratch with paired bindings or a custom directive, and apply it via ngModel to form controls.
How it connects
Connects property binding, event binding, ngModel, HTML forms, signals, and attribute directives.

Also explained in

Compare how 2 books explain two-way binding →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Pro Angular 16. The section links point to the parts of the book it draws on.