В чём разница между property binding, event binding и two-way binding?

В Angular привязка данных (data binding) представляет собой механизм синхронизации данных между компонентом (моделью) и шаблоном (представлением). Основными видами привязки являются property binding, event binding и two-way binding. Они различаются направлением потока данных и способом взаимодействия между моделью и DOM.

1. Property Binding (Привязка к свойствам)

Суть:

Позволяет передавать данные из компонента в DOM-элемент или дочерний компонент.

Синтаксис:

\[elementProperty\]="componentProperty"

или

\[disabled\]="isDisabled"
\[src\]="imageUrl"
\[ngClass\]="classList"

Пример:

export class AppComponent {
isDisabled = true;
imageUrl = 'https://example.com/image.png';
}
<button \[disabled\]="isDisabled">Кнопка</button>
<img \[src\]="imageUrl">

Особенности:

  • Односторонний поток данных: из модели в шаблон.

  • Работает с DOM-свойствами, а не HTML-атрибутами.

  • Можно использовать с любыми свойствами DOM, директив, компонентов.

2. Event Binding (Привязка к событиям)

Суть:

Позволяет передавать данные из шаблона в компонент, реагируя на события DOM.

Синтаксис:

(eventName)="handler($event)"

Пример:

export class AppComponent {
onClick(event: Event) {
console.log('Кнопка нажата', event);
}
}
<button (click)="onClick($event)">Нажми меня</button>

Особенности:

  • Односторонний поток данных: от шаблона к компоненту.

  • Используется для подписки на стандартные события (click, input, change, submit) и кастомные (@Output).

  • $event содержит объект события DOM или данные, переданные из дочернего компонента.

3. Two-Way Binding (Двусторонняя привязка)

Суть:

Объединяет property binding и event binding в один синтаксис — позволяет синхронизировать значения между компонентом и шаблоном в обе стороны.

Синтаксис:

\[(ngModel)\]="componentProperty"

Пример:

export class AppComponent {
username = '';
}
<input \[(ngModel)\]="username">
<p>Привет, {{ username }}</p>

Как это работает внутри:

\[(ngModel)\]="username"  это синтаксический сахар для:
<input \[ngModel\]="username" (ngModelChange)="username = $event">

Особенности:

  • Двунаправленная синхронизация: изменения в компоненте обновляют DOM, и наоборот.

  • Требует подключения FormsModule из @angular/forms:

import { FormsModule } from '@angular/forms';
@NgModule({ imports: \[FormsModule\] })
  • Работает с директивами, которые реализуют интерфейс ControlValueAccessor.

4. Сравнение по направлениям данных

Вид привязки Поток данных Сценарий применения
Property Binding Компонент → Шаблон Отображение данных, управление DOM-свойствами
--- --- ---
Event Binding Шаблон → Компонент Обработка событий от пользователя
--- --- ---
Two-Way Binding Компонент ↔ Шаблон Формы, интерактивные поля, двусторонняя синхронизация
--- --- ---

5. Пример сравнения в одном компоненте

export class AppComponent {
title = 'Angular';
inputValue = '';
updateValue(event: Event) {
const target = event.target as HTMLInputElement;
this.inputValue = target.value;
}
}
<!-- Property Binding -->
<input \[value\]="inputValue">
<!-- Event Binding -->
<input (input)="updateValue($event)">
<!-- Two-Way Binding -->
<input \[(ngModel)\]="inputValue">

6. Использование в компонентах

Property binding и event binding могут использоваться при взаимодействии с дочерними компонентами:

<app-counter \[count\]="initialCount" (change)="onCounterChange($event)"></app-counter>
// В дочернем компоненте
@Input() count: number;
@Output() change = new EventEmitter<number>();

Two-way binding можно настроить вручную через @Input() и @Output():

<app-counter \[(count)\]="myCount"></app-counter>
@Input() count: number;
@Output() countChange = new EventEmitter<number>();

Angular интерпретирует [(count)]="value" как:

\[count\]="value" (countChange)="value = $event"

7. Отличие от обычных HTML-атрибутов

  • [attr.name] — привязка к **атрибуту HTML
    **
  • [property] — привязка к **DOM-свойству
    **
  • attr.value="..." — обычный HTML-атрибут (работает только при инициализации)

  • [value]="..." — property binding (обновляется при каждом изменении данных)

8. Примеры использования всех типов одновременно

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

или с двухсторонней привязкой:

<input \[(ngModel)\]="name">

В обоих случаях значение name будет синхронизировано с содержимым поля ввода.

9. Влияние на производительность

  • Property binding и event binding вызывают срабатывание механизма обнаружения изменений (Change Detection);

  • Two-way binding может быть менее производительным при неправильном использовании (например, в больших формах), особенно при частых обновлениях;

  • Для оптимизации используют ChangeDetectionStrategy.OnPush, реактивные формы или ручное управление событиями.