首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不使用ControlValueAccessor的反应性表单

不使用ControlValueAccessor的反应性表单
EN

Stack Overflow用户
提问于 2021-09-13 10:54:57
回答 2查看 1.3K关注 0票数 4

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

代码语言:javascript
复制
    @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看起来是:

代码语言:javascript
复制
    @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;
    }

当我运行应用程序时,我希望textbox中填充值测试。

有人能解释一下为什么不是吗?

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-13 12:21:32

您只需将值this.form.get('name').setValue(this.model.name);移动到ngAfterViewInit而不是ngOnInit,或者在它之后调用:

代码语言:javascript
复制
this.form.updateValueAndValidity();

顺便说一句,这里有两个音符你应该处理好:

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

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

Stack Overflow用户

发布于 2021-09-13 11:13:28

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

代码语言:javascript
复制
writeValue(obj: any): void {
  if (obj !== this._value) {
    this._value = obj;
  }
}

不要忘记为NG_VALUE_ACCESSOR添加提供程序,并添加多提供者来扩展现有的提供程序。(参见参考资料https://almerosteyn.com/2016/04/linkup-custom-control-to-ngcontrol-ngmodel)

代码语言:javascript
复制
@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;
    }
  }

  ...
}

基于StackBlitz的样本解决方案

参考文献

使用control访问器将您的自定义控件连接到ngModel。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69161446

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档