Angular 2.重建表单控件

时间:2017-10-20 20:21:15

标签: angular angular-forms

有没有办法强制Angular表单重新创建它的控件?我的意思是创建新实例?看起来它只在初始加载时创建它们。不确定我是否真的需要它,但这是我的问题:

我有一个"编辑"我需要编辑的项目@Input() set item(editItem)的控件。我从其父项设置此项,控件应重置表单值。 在表单中,我使用自己的自定义下拉控件,该控件具有可绑定的选项列表。

通常它看起来像这样:

@Component({
  template:`
    <form [formGroup]="form">
      <my-control [items]="items" formControlName="itemId"></app-combobox>
    </form>
  `

export class EditComponent implements OnInit {
  items = [{text: 'Item 1', itemId: 1}, {text: 'Item 2', itemId: 2}];

  @Input() set editItem(item) {
    //if some logic...
      this.items = [{text: 'Item 3', itemId: 3}, {text: 'Item 4', itemId: 4}];

    this.initForm(item);
  }

  constructor(private _fb: FormBuilder) {}

  ngOnInit(): void {
    this.initForm();
  }

  initForm(item?) {
    this.form = this._fb.group({
      // itemId could differ and should be in the items list before binding happens
      'itemId': [item ? item.itemId : null]
  }
}

和控件:

export class ComboboxComponent implements ControlValueAccessor {
  items = [];

  @Input() set items(list[]) {
    this.items = list;
    this.updateValue();
  }

  // ControlValueAccessor implementation
  writeValue(value: any) {
     this.updateValue();
  }

  updateValue() {
    // here we try to use a newly updated list (but it's not updated yet!)
  }
}

问题是即使我在创建新的formGroup之前设置了一个新的项目列表,表单绑定也会在我的项目列表绑定之前发生。我的下拉控件上的writeValue之前会调用ControlValueAccessor界面中的@Input() set items([])方法。

我可以在setTimeout(() => this.updateValue())内使用writeValue,这似乎有所帮助,但我不喜欢这个解决方案。如何在表单绑定之前进行控件属性绑定?在initForm()无效之前调用超时或强制Angular检测更改。

1 个答案:

答案 0 :(得分:3)

我做类似的方法是在ngOnInit中设置表格结构,如下所示:

ngOnInit(): void {
    this.productForm = this.fb.group({
        productName: ['', [Validators.required,
                           Validators.minLength(3),
                           Validators.maxLength(50)]],
        productCode: ['', Validators.required],
        starRating: ['', NumberValidators.range(1, 5)],
        tags: this.fb.array([]),
        description: ''
    });

然后,当数据发生变化时,我不会改变它。相反,我只是使用以下代码更新表单上的值:

onProductRetrieved(product: IProduct): void {
    if (this.productForm) {
        this.productForm.reset();
    }
    this.product = product;

    // Update the data on the form
    this.productForm.patchValue({
        productName: this.product.productName,
        productCode: this.product.productCode,
        starRating: this.product.starRating,
        description: this.product.description
    });
    this.productForm.setControl('tags', this.fb.array(this.product.tags || []));
}

您可以从@Input设置器中调用它。