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

前端 未结 2 998
太阳男子
太阳男子 2021-01-03 11:04

I\'m trying to inverse the way forms controls are registering themselves onto a FormGroup, so that instead of having to

@Component({..., templ         


        
2条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-01-03 11:44

    I ran into the same issue. Odd that there aren't more Stackoverflow posts about this. The above answer did not work for me, but this is how I solved it in the case that there are more out there.

    @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 this hybrid component could be used like:

    @Component({
      selector: 'app',
      template: `
        
    ` class AppComponent { formGroup: FormGroup constructor(fb: FormBuilder) { this.form = this.fb.group({}); } }

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

提交回复
热议问题