在Angular 2+中扩展FormControlDirective [英] Extending FormControlDirective in Angular 2+

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

问题描述

我正在研究这个问题,试图找出如何扩展FormControlDirective:

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指令的访问器( 内置指令的模式).

The formControl \ formControlName selectors appear in one more place - the value accessor. In order your directive to work you should implement all default value accessors for the hybridFormControl directive ( following the pattern for the built-in directives).

这是我的代码:

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的问题非常相似,它与@ronif的 Plunker 相似.即使我要传递<input type="text" class="form-control" appControl="firstName">之类的值,set appControl也会运行,并且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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆