本文介绍了在 Angular 2+ 中扩展 FormControlDirective的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在看这个问题,试图弄清楚如何扩展 FormControlDirective:尝试扩展 FormControlDirective 以实现我自己的 FormControl 指令导致绑定错误.

I'm looking at this question, trying to figure out how to extend FormControlDirective: Attempting to extend FormControlDirective to implement my own FormControl directive results in faulty binding.

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

There is an answer, but I'm not sure what is meant by:

formControl \ formControlName 选择器出现在另外一个地方 - 价值存取器.为了您的指令工作,您应该实现所有默认值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 一起使用.

It is very similar to @ronif's Plunker from his question. set appControl does run, even though I'm passing a value like <input type="text" class="form-control" appControl="firstName">, and FormControlDirective._rawValidators seems to always be an empty array, even though the FormGroup works with the standard FormControlDirective.

我将如何实现所有默认值访问器"?

How would I go about 'implementing all default value accessors'?

推荐答案

如果其他人遇到这样的情况,这里是我想出的解决方案.我想从子表单控件元素动态创建表单控件模型.这样我就不必编写包含大量表单控件字段的初始模型,同时仍能从反应式表单模型中受益.这是如何扩展 FormControlName 类:

In case anyone else runs into something like this, here is the solution I came up with. I wanted to dynamically create a form control model from the child form control element. This is so I didn't have to write an initial model with tons of form control fields while still getting the benefit of the reactive forms model. This is how to extend the FormControlName class:

@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;
  }
}

你会使用这个新的混合指令,如:

And you would use this new hybrid directive like:

@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('')); 代码行.我还没有验证这一点,但希望这可以帮助遇到这个问题的其他人.

You will need to modify this.formGroup.registerControl(name, this.fb.control('')); line of code if you want to pass validators. I haven't verified this, but hopefully this helps someone else who runs across this question.

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

这篇关于在 Angular 2+ 中扩展 FormControlDirective的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 06:25