尝试扩展 FormControlDirective 以实现我自己的 FormControl 指令导致绑定错误

Attempting to extend FormControlDirective to implement my own FormControl directive results in faulty binding

我正在尝试反转表单控件将自己注册到 FormGroup 上的方式,这样就不必

@Component({..., template: `<input [formControl]="myControl"`}    
...

@Component({..., template: `<input [formControName]="myControlName"`}    
...

我可以

@Component({..., template: `<input myFormControl`}    
...

并让我的指令为我创建并添加 FormControl

最好用这个Plunker来解释。

将视图绑定到表单模型似乎不起作用,如您所见,更改输入不会更改表单模型值。

调试显示没有 valueAccessor 注入到构造函数中(不同于直接使用基础 FormControlDirective class)。

如果您想知道,我的最终目标是拥有一个父级自定义组组件,该组件 @ViewChildren(MyFormDirective) 并将它们全部动态添加到它创建的表单中。

你快到了。不过还有一个窍门。该输入元素没有 DefaultValueAccessor,因此构造函数参数填充有 null 值。

formControl \ formControlName 选择器又出现在一处 - the value accessor。为了使您的指令起作用,您应该为 hybridFormControl 指令实现所有默认值访问器(遵循内置指令的模式)。

P.S 我认为您的指令提供者应该更正为

providers: [{
    provide: NgControl, //<-- NgControl is the key
    useExisting: forwardRef(() => HybridFormControlDirective)
}]

我运行遇到了同样的问题。奇怪的是没有更多关于此的 Whosebug 帖子。上面的答案对我不起作用,但这是我在有更多答案的情况下解决的方法。

@Directive({
  selector: '[hybridFormControl]'
})
class HybridFormControl Directive extends FormControlName implements ControlValueAccessor, OnChanges {
  @Input('hybridFormControl') name: string;

  onChange;
  onTouched;

  constructor(
      @Optional() protected formGroupDirective: FormGroupDirective,
      @Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[],
      private fb: FormBuilder,
      private renderer: Renderer2,
      private element: ElementRef
  ) {
    super(formGroupDirective, [], [], valueAccessors, null);
    this.valueAccessor = this;
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (!this._registered) {
      // dynamically create the form control model on the form group model.
      this.formGroup = this.formGroupDirective.form;
      this.formGroup.registerControl(name, this.fb.control(''));
      this._registered = true;
    }

    // IMPORTANT - this ties your extended form control to the form control 
    // model on the form group model that we just created above. Take a look
    // at Angular github source code.
    super.ngOnChanges(changes); 
  }

  @HostListener('input', ['$event.target.value'])
  @HostListener('change', ['$event.target.value'])
  onInput(value): void {
    this.onChange(modelValue);
  }

  writeValue(value): void {
    const element = this.element.nativeElement;
    this.renderer.setProperty(element, 'value', value);
  }

  registerOnChange(fn): void {
    this.onChange = fn;
  }

  registerOnTouched(fn): void {
    this.onTouched = fn;
  }
}

这个混合组件可以像这样使用:

@Component({
  selector: 'app',
  template: `
    <form formGroup=[formGroup]>
      <input type="text" hybridFormControl="myName">
    </form>
  `
class AppComponent {
  formGroup: FormGroup

  constructor(fb: FormBuilder) {
    this.form = this.fb.group({});
  }
}

来源:https://github.com/angular/angular/blob/master/packages/forms/src/directives/reactive_directives/form_control_name.ts#L212