3

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

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

或者

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

我可以

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

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

最好用这个Plunker来解释。

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

调试它表明没有valueAccessor注入构造函数(与直接使用基FormControlDirective类时不同)。

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

4

2 回答 2

2

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

formControl\选择器formControlName出现在另一个地方 -值访问器。为了使您的指令正常工作,您应该为指令实现所有默认值访问器hybridFormControl(遵循内置指令的模式)。

PS我相信您的指令提供者应该更正为

providers: [{
    provide: NgControl, //<-- NgControl is the key
    useExisting: forwardRef(() => HybridFormControlDirective)
}]
于 2017-06-29T14:49:19.360 回答
0

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

@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

于 2020-01-23T17:21:21.643 回答