在Angular 2+中扩展FormControlDirective

时间:2018-03-22 23:04:55

标签: angular angular-directive angular-reactive-forms angular-forms

我正在查看这个问题,试图找出如何扩展FormControlDirective:Attempting to extend FormControlDirective to implement my own FormControl directive results in faulty binding

有一个答案,但我不确定是什么意思:

  

formControl \ formControlName选择器出现在另一个中   地方 - the value accessor。   为了使您的指令起作用,您应该实现所有默认值   hybridFormControl指令的访问器(在...之后)   内置指令的模式。)

这是我的代码:

export const formControlBinding: any = {
  provide: NgControl,
  useExisting: forwardRef(() => ControlDirective)
};

@Directive({
  selector: '[appControl]',
  providers: [formControlBinding],
  exportAs: 'ngForm'
})
export class ControlDirective extends FormControlDirective implements OnInit {

  constructor(
    @Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>,
    @Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: Array<AsyncValidator|AsyncValidatorFn>,
    @Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[],
    public renderer: Renderer2,
    public hostElement: ElementRef,
  ) {
    super(validators, asyncValidators, valueAccessors);
  }

  @Input() set appControl(form: FormControl) {
    console.log(form);
    this.form = form;
  }
}

他的问题与@ ronif的Plunker非常相似。 set appControl确实在运行,即使我传递了<input type="text" class="form-control" appControl="firstName">之类的值,而FormControlDirective._rawValidators似乎总是一个空数组,即使FormGroup适用于标准FormControlDirective

我将如何实施所有默认值访问器&#39;?

1 个答案:

答案 0 :(得分:1)

万一其他人遇到类似问题,这是我想出的解决方案。我想根据子表单控件元素动态创建表单控件模型。这样一来,我不必编写具有大量表单控制字段的初始模型,而仍然可以受益于反应式表单模型。这是扩展FormControlName类的方法:

@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({});
  }
}

如果要通过验证程序,则需要修改this.formGroup.registerControl(name, this.fb.control(''));行代码。我尚未对此进行验证,但是希望这可以帮助遇到此问题的其他人。

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