【问题标题】:Reactive Forms Not Working with ControlValueAccessor反应式表单不适用于 ControlValueAccessor
【发布时间】:2021-11-08 16:09:42
【问题描述】:

我已经构建了一个名为TextBox的控件,为简单起见,我将这里只贴出控件的相关部分。

    @Component({
      selector: 'app-textbox',
      template:
      `
        <input [(ngModel)]="value" [disabled]="disabled" />
      `,
      styleUrls: ['./textbox.component.css']
    })
    export class TextboxComponent implements OnInit, ControlValueAccessor {
    
      constructor() { }
      writeValue(obj: any): void {
        this._value = obj;
      }
      registerOnChange(fn: any): void {
        this.onChange = fn;
      }
      registerOnTouched(fn: any): void {
        this.onTouch = fn;
      }
      setDisabledState?(isDisabled: boolean): void {
        this.disabled = isDisabled;
      }
    
      disabled = false;
    
      onChange:()=>{}
      onTouch:()=>{};
    
      private _value:string;
      public get value():string {
        return this._value
      } 
      public set value(value:string){
        this._value = value;
      }
    
      ngOnInit(): void {
      }

我的 app.component.ts 看起来像:

    @Component({
      selector: 'app-root',
      template:
      `
        <form [formGroup]="form" novalidate>
          <div>
            <label >Name</label>
            <app-textbox formControlName="name"></app-textbox>
          </div>
        </form>
      `,
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit{
      /**
       *
       */
      constructor(private formBuilder:FormBuilder) {
      }
    
      form = this.formBuilder.group({
        name:['', Validators.required]
      })
    
      model:NameModel = {
        name:'test'
      }
    
      ngOnInit(): void {
        this.form.get('name').setValue(this.model.name);
      }
    }
    
    interface NameModel{
      name:string;
    }

当我运行应用程序时,我希望文本框会填充值 test。

有人可以解释为什么不是吗?

我会在this.form.get('name')?.value 得到正确值时添加。

【问题讨论】:

  • 尝试将this.form.get('name').setValue(this.model.name); 移动到ngAfterViewInit 而不是ngOnInit
  • 谢谢@AmerYousuf 那是anwser。如果您将其添加到 anwser,我会接受它。
  • 谢谢,我在回答中添加了一些注释。

标签: angular typescript angular-reactive-forms angular-forms


【解决方案1】:

您只需将值this.form.get('name').setValue(this.model.name); 设置为ngAfterViewInit 而不是ngOnInit,否则您必须调用它:

this.form.updateValueAndValidity();

顺便说一句,这里有两个注意事项你应该注意它们:

  1. TextboxComponent 中更改值后,您错过了将值写回表单控件,因此您必须在值设置器中调用已注册的 onChange 方法,如下所示:
private _value: string;
public get value(): string {
  return this._value;
}
public set value(value: string) {
  this._value = value;
  this.onChange(value);
}
  1. 在您的情况下,最好在ngOnInit 中初始化FormGroup,并直接设置name 的默认值,如下所示:
form: FormGroup;

ngOnInit(): void {
  this.form = this.formBuilder.group({
    name: [this.model.name, Validators.required],
  });
}

【讨论】:

    【解决方案2】:

    writeValue(obj)中,需要将接收到的输入obj分配给this._value

    writeValue(obj: any): void {
      if (obj !== this._value) {
        this._value = obj;
      }
    }
    

    不要忘记为NG_VALUE_ACCESSOR 添加提供者和扩展现有提供者的多提供者。 (参考参考资料1

    @Component({
      selector: 'app-textbox',
      template: `
        <input [(ngModel)]="value" [disabled]="disabled" />
      `,
      styleUrls: ['./textbox.component.css'],
      providers: [
        {
          provide: NG_VALUE_ACCESSOR,
          useExisting: forwardRef(() => TextboxComponent),
          multi: true
        }
      ]
    })
    export class TextboxComponent implements OnInit, ControlValueAccessor {
    
      writeValue(obj: any): void {
        if (obj !== this.value) {
          this._value = obj;
        }
      }
    
      ...
    }
    

    Sample Solution on StackBlitz


    参考

    Connect your custom control to ngModel with Control Value Accessor.

    【讨论】:

      猜你喜欢
      • 2020-07-07
      • 2019-11-25
      • 2020-04-19
      • 2020-01-29
      • 2019-05-20
      • 1970-01-01
      • 2017-10-03
      • 1970-01-01
      • 2019-03-08
      相关资源
      最近更新 更多