forms - Angular:实现嵌套表单的复合ControlValueAccessor

标签 forms angular

在 Angular Connect 2017 演示文稿中介绍了用于实现嵌套表单的 ControlValueAccessor 组合。

https://docs.google.com/presentation/d/e/2PACX-1vTS20UdnMGqA3ecrv7ww_7CDKQM8VgdH2tbHl94aXgEsYQ2cyjq62ydU3e3ZF_BaQ64kMyQa0INe2oI/pub?slide=id.g293d7d2b9d_1_1532

在此演示中,演讲者展示了一种实现具有多个值(不仅是单个字符串值,而且具有两个字符串字段,如街道和城市)的自定义表单控件的方法。我想实现它,但我被卡住了。示例应用程序在这里,有人知道我应该更正什么吗?

https://stackblitz.com/edit/angular-h2ehwx

父组件

@Component({
  selector: 'my-app',
  template: `
    <h1>Form</h1>
    <form [formGroup]="form" (ngSubmit)="onSubmit(form.value)" novalidate>
      <label>name</label>
      <input formControlName="name">
      <app-address-form formControlName="address"></app-address-form>
      <button>submit</button>
    </form>
  `,
})
export class AppComponent  {
  @Input() name: string;
  submitData = '';
  form: FormGroup;

  constructor(private fb: FormBuilder) {
    this.form = fb.group({
      name: 'foo bar',
      address: fb.group({
        city: 'baz',
        town: 'qux',
      })
    });
  }

  onSubmit(v: any) {
    console.log(v);
  }
}

嵌套表单组件

@Component({
  selector: 'app-address-form',
  template: `
    <div [formGroup]="form">
      <label>city</label>
      <input formControlName="city" (blur)="onTouched()">
      <label>town</label>
      <input formControlName="town" (blur)="onTouched()">
    </div>
  `,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      multi: true,
      useExisting: forwardRef(() => AddressFormComponent)
    }
  ]
})
export class AddressFormComponent implements ControlValueAccessor {
  form: FormGroup;

  onTouched: () => void = () => {};

  writeValue(v: any) {
    this.form.setValue(v, { emitEvent: false });
  }

  registerOnChange(fn: (v: any) => void) {
    this.form.valueChanges.subscribe(fn);
  }

  setDisabledState(disabled: boolean) {
    disabled ? this.form.disable() : this.form.enable();
  }

  registerOnTouched(fn: () => void) {
    this.onTouched = fn;
  }
}

和我收到的错误信息

ERROR TypeError: Cannot read property 'setValue' of undefined
at AddressFormComponent.writeValue (address-form.component.ts:32)
at setUpControl (shared.js:47)
at FormGroupDirective.addControl (form_group_directive.js:125)
at FormControlName._setUpControl (form_control_name.js:201)
at FormControlName.ngOnChanges (form_control_name.js:114)
at checkAndUpdateDirectiveInline (provider.js:249)
at checkAndUpdateNodeInline (view.js:472)
at checkAndUpdateNode (view.js:415)
at debugCheckAndUpdateNode (services.js:504)
at debugCheckDirectivesFn (services.js:445)

我认为应该以某种方式将 FormGroup 实例注入(inject)到嵌套表单组件中......

最佳答案

几个问题,在您的 AppComponent 上将您的 FormBuilder 更改为:

this.form = fb.group({
  name: 'foo bar',
  address: fb.control({ //Not using FormGroup
    city: 'baz',
    town: 'qux',
  })
});

在您的 AddressFormComponent 上,您需要像这样初始化您的 FormGroup:

form: FormGroup = new FormGroup({
    city: new FormControl,
    town: new FormControl
});

这是您的示例的分支:https://stackblitz.com/edit/angular-np38bi

关于forms - Angular:实现嵌套表单的复合ControlValueAccessor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47297407/

相关文章:

angular - 如何让 Leaflet Marker-Cluster Freezable 方法显示在 VS Code IntelliSense 中

angular - 我无法在 Angular 中动态更改语言

Django - 生日 fildset 作为表单小部件

Javascript 表单验证服务器端,可能吗?

angular - 当用户路由到不同的页面时,setTimeout 继续,如何在 Angular typescript 中清除超时?

javascript - Angular 6 - 指令输出在同一时刻触发所有组件

javascript - 使用 javascript 形成 "action"

javascript - 表单的 reset() 方法不会重置具有 value 属性的输入

html - 在 IE8 中自定义下拉列表高度

javascript - Firebase 更新数据,但几秒钟后将其更改回原始值 "angularFire"