首页 > 解决方案 > 简单的控制值访问器

问题描述

什么是 Angular 的控制值访问器

我尝试过@input、@output 方法,但在验证过程中变得复杂,特别是对于 ngModel

期望包含第 3 方 UI 控件的包装器组件能够轻松工作

标签: angular

解决方案


简单来说,控制值访问器: 目的:拥有一个自定义 UI 子组件,它是一个使用第三方 UI 小部件的包装器,可能像 PrimeNg、ngx-bootstrap 的 DatePicker。包装器可以轻松地与表单控件(父组件)同步,而无需使用 @Inputs/Outputs。主要是,您将如何通知父母有关验证的信息。轻松通过 CVA。

示例:假设您想从 ngx-bootstrap 构建一个 datepicker,如下所示:假设您有一个使用自定义 DatePicker 的表单:

表格.ts:

currentDate: Date = new Date();
onDateChanged($event){
  // do something with the received date..Maybe call an api for the selectedDate's data
}

表格.html:

<custom-date-picker id="selectedDate" name="fieldName" [(ngModel)]="currentDate" (onDateChanged)="onDateChanged($event)"></custom-date-picker>

创建一个包装组件:CustomDatePicker.ts:

@Component({
  selector: 'custom-date-picker',
  templateUrl: 'custom-date-picker.component.html',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => IpxDatePickerComponent),
      multi: true
    }
  ]
})

export class CustomDatePickerComponent implements ControlValueAccessor {
   onChanged: any = () => {};
  // tslint:disable-next-line:no-empty
  onTouched: any = () => {};

  writeValue(obj: any): void {
    if (obj) {
      this.selectDate(obj);
    }
  }
  registerOnChange(fn: any): void {
    this.onChanged = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
  // tslint:disable-next-line:no-empty
  setDisabledState?(isDisabled: boolean): void {}

  selectDate(val): void {
    this.selectedDate = val;
  }

  dateChanged = (e: Date): void => {
    if (e) {
      this.onChanged(e);// this statement should have ideally set your parent forms ngModel variable to the new selected date.
      this.onDateChanged.emit(e);
    }
  };
}

CustomDatePicker.html:

 <input type="text" #datePicker="bsDatepicker" placeholder="Datepicker"  (bsValueChange)="dateChanged($event)" [(ngModel)]="selectedDate" [bsConfig]="bsConfig" />

就是这样,现在如果您看到,您的表单的 ngModel 将同步。并且子控件和父控件将与 selectedDate 以及 touch 等验证同步。

实际上,我发现这种方法很有用,因为在使用常规 @inputs、@outputs 实现时,我发现了很多同步问题。

我们现在甚至可以通过 CVA 使用它们,但它们主要用于操作其他数据而不是包装目的(在这种情况下为日期)


推荐阅读