Angular:复合 ControlValueAccessor 实现嵌套表单 [英] Angular: composite ControlValueAccessor to implement nested form

查看:21
本文介绍了Angular:复合 ControlValueAccessor 实现嵌套表单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

父组件

@Component({选择器:'我的应用',模板:`<h1>形式</h1><form [formGroup]="form" (ngSubmit)="onSubmit(form.value)" novalidate><标签>名称</标签><input formControlName="name"><app-address-form formControlName="address"></app-address-form><按钮>提交</表单>`,})导出类 AppComponent {@Input() 名称:字符串;提交数据 = '';表格:表格组;构造函数(私人FB:FormBuilder){this.form = fb.group({name: 'foo bar',地址:fb.group({城市: 'baz',城镇:'qux',})});}onSubmit(v: 任何) {控制台日志(v);}}

嵌套表单组件

@Component({选择器:'app-address-form',模板:`<div [formGroup]="表单"><label>城市</label><input formControlName="city" (blur)="onTouched()"><label>城镇</label><input formControlName="town" (blur)="onTouched()">

`,提供者:[{提供:NG_VALUE_ACCESSOR,多:真实,useExisting: forwardRef(() => AddressFormComponent)}]})导出类 AddressFormComponent 实现 ControlValueAccessor {表格:表格组;onTouched: () =>void = () =>{};写值(v:任何){this.form.setValue(v, {emitEvent: false });}registerOnChange(fn: (v: any) => void) {this.form.valueChanges.subscribe(fn);}setDisabledState(禁用:布尔值){禁用?this.form.disable() : this.form.enable();}registerOnTouched(fn: () => void) {this.onTouched = fn;}}

和我收到的错误信息

错误类型错误:无法读取未定义的属性setValue"在 AddressFormComponent.writeValue (address-form.component.ts:32)在 setUpControl (shared.js:47)在 FormGroupDirective.addControl (form_group_directive.js:125)在 FormControlName._setUpControl (form_control_name.js:201)在 FormControlName.ngOnChanges (form_control_name.js:114)在 checkAndUpdateDirectiveInline (provider.js:249)在 checkAndUpdateNodeInline (view.js:472)在 checkAndUpdateNode (view.js:415)在 debugCheckAndUpdateNode (services.js:504)在 debugCheckDirectivesFn (services.js:445)

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

解决方案

耦合问题,在你的 AppComponent 上将你的 FormBuilder 更改为:

this.form = fb.group({name: 'foo bar',地址:fb.control({//不使用FormGroup城市: 'baz',城镇:'qux',})});

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

form: FormGroup = new FormGroup({城市:新的 FormControl,城镇:新的 FormControl});

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

Composition of ControlValueAccessor to implement nested form is introduced in an Angular Connect 2017 presentation.

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

In this presentation, the speaker showed a way to implement custom form control which have multiple value (not only single string value but has two string field, like street and city). I want to implement it but I'm stuck. Sample app is here, does anybody know what should I correct?

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

parent component

@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);
  }
}

nested form component

@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;
  }
}

and error message I got

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)

I think FormGroup instance should be injected to nested form component somehow...

解决方案

Couple issues, on your AppComponent change your FormBuilder to:

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

On your AddressFormComponent you need to initialize your FormGroup like so:

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

Here's the fork of your sample: https://stackblitz.com/edit/angular-np38bi

这篇关于Angular:复合 ControlValueAccessor 实现嵌套表单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆