Two way binding é um atalho para simultaneamente vincular um valor a um elemento, enquanto também dá a esse elemento a capacidade de propagar mudanças de volta através desse binding.
Sintaxe
A sintaxe para two-way binding é uma combinação de colchetes e parênteses, [()]. Ela combina a sintaxe de property binding, [], e a sintaxe de event binding, (). A comunidade Angular informalmente se refere a essa sintaxe como "banana-in-a-box".
Two-way binding com form controls
Desenvolvedores comumente usam two-way binding para manter os dados do component sincronizados com um form control enquanto o usuário interage com o control. Por exemplo, quando um usuário preenche um input de texto, ele deve atualizar o estado no component.
O exemplo a seguir atualiza dinamicamente o atributo firstName na página:
import { Component } from '@angular/core';import { FormsModule } from '@angular/forms';@Component({ imports: [FormsModule], template: ` <main> <h2>Hello {{ firstName }}!</h2> <input type="text" [(ngModel)]="firstName" /> </main> `})export class AppComponent { firstName = 'Ada';}
Para usar two-way binding com form controls nativos, você precisa:
- Importar o
FormsModulede@angular/forms - Usar a directive
ngModelcom a sintaxe de two-way binding (ex.,[(ngModel)]) - Atribuí-lo ao estado que você quer atualizar (ex.,
firstName)
Uma vez configurado, o Angular garantirá que quaisquer atualizações no input de texto sejam refletidas corretamente dentro do estado do component!
Saiba mais sobre NgModel na documentação oficial.
Two-way binding entre components
Aproveitar two-way binding entre um component pai e filho requer mais configuração comparado a elementos de formulário.
Aqui está um exemplo onde o AppComponent é responsável por definir o estado inicial do count, mas a lógica para atualizar e renderizar a UI do contador reside principalmente dentro do seu component filho CounterComponent.
// ./app.component.tsimport { Component } from '@angular/core';import { CounterComponent } from './counter/counter.component';@Component({ selector: 'app-root', imports: [CounterComponent], template: ` <main> <h1>Counter: {{ initialCount }}</h1> <app-counter [(count)]="initialCount"></app-counter> </main> `,})export class AppComponent { initialCount = 18;}
// './counter/counter.component.ts';import { Component, model } from '@angular/core';@Component({ selector: 'app-counter', template: ` <button (click)="updateCount(-1)">-</button> <span>{{ count() }}</span> <button (click)="updateCount(+1)">+</button> `,})export class CounterComponent { count = model<number>(0); updateCount(amount: number): void { this.count.update(currentCount => currentCount + amount); }}
Habilitando two-way binding entre components
Se quebrarmos o exemplo acima em sua essência, cada two-way binding para components requer o seguinte:
O component filho deve conter uma propriedade model.
Aqui está um exemplo simplificado:
// './counter/counter.component.ts';import { Component, model } from '@angular/core';@Component({ /* Omitido para brevidade */ })export class CounterComponent { count = model<number>(0); updateCount(amount: number): void { this.count.update(currentCount => currentCount + amount); }}
O component pai deve:
- Envolver o nome da propriedade
modelna sintaxe de two-way binding. - Atribuir uma propriedade ou um signal à propriedade
model.
Aqui está um exemplo simplificado:
// ./app.component.tsimport { Component } from '@angular/core';import { CounterComponent } from './counter/counter.component';@Component({ selector: 'app-root', imports: [CounterComponent], template: ` <main> <app-counter [(count)]="initialCount"></app-counter> </main> `,})export class AppComponent { initialCount = 18;}