Angular 中的双向绑定:使用 ngModel 实现表单控件

288 阅读2分钟

在 Angular 中,ngModel 指令为我们提供了双向绑定的功能,使得表单控件的值和组件中的变量可以保持同步。本文将通过一个简单的示例来总结如何实现 ngModel 双向绑定。

什么是双向绑定?

双向绑定是指数据在视图(模板)和模型(组件)之间的双向流动。任何一方的改变都会立即反映到另一方。例如,当用户在表单输入框中输入内容时,组件的对应变量会自动更新,反之亦然。

组件实现

在组件中,我们需要定义一些属性和方法,以支持 ngModel 的双向绑定。以下是一个基本的实现示例:

import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

/**
 * 自定义表单控件组件
 */
@Component({
  selector: 'app-custom-input',
  template: `
    <div *ngFor="let option of options">
      <input type="checkbox" [checked]="option.checked" (change)="checkedChange()" />
      {{ option.value }}
    </div>
  `,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CustomInputComponent),
      multi: true
    }
  ]
})
export class CustomInputComponent implements ControlValueAccessor {
  /** 当前选中的值 */
  value: any[] = [];

  /** 保存 onChange 回调函数 */
  onChange: (value: any[]) => void = () => {};

  /** 保存 onTouch 回调函数 */
  onTouch: () => void = () => {};

  /** 控件选项示例 */
  options = [
    { value: '选项1', checked: false },
    { value: '选项2', checked: false },
    { value: '选项3', checked: false }
  ];

  /** 将新值写入组件 */
  writeValue(value: any[]): void {
    this.value = value;
    this.options.forEach(option => {
      option.checked = this.value.includes(option.value);
    });
  }

  /** 注册当值更改时触发的回调函数 */
  registerOnChange(fn: (value: any[]) => void): void {
    this.onChange = fn;
  }

  /** 注册当控件被触摸时触发的回调函数 */
  registerOnTouched(fn: () => void): void {
    this.onTouch = fn;
  }

  /**
   * 选中状态改变
   */
  checkedChange(): void {
    this.value = this.options.filter(item => item.checked).map(item => item.value);
    // 更新数据
    this.onChange(this.value);
    this.onTouch();
  }
}

关键方法解析

  • writeValue(value: any[]):此方法用于将外部值写入组件。当父组件更新值时,此方法会被调用。
  • **registerOnChange(fn: (value: any[]) => void)**:此方法用于注册一个回调函数,该函数会在值变化时被调用。它允许父组件接收组件中的值变化。
  • **registerOnTouched(fn: () => void)**:此方法用于注册一个回调函数,当控件被触摸时会调用此函数,通常用于标记控件为“脏”。
  • **checkedChange()**:当选中状态发生变化时,更新当前选中的值,并调用 onChangeonTouch 回调。

在模板中使用

在父组件中使用自定义控件时,可以通过 ngModel 实现双向绑定,如下所示:

<app-custom-input [(ngModel)]="selectedValues"></app-custom-input>

在父组件中,selectedValues 变量将与自定义控件的选中值保持同步。

总结

通过自定义表单控件的实现,我们可以利用 Angular 的 ngModel 指令轻松实现双向数据绑定。这使得组件与表单控件之间的交互更加直观和高效。