forms - 각도:중첩 된 양식을 구현하는 복합 ControlValueAccessor




angular (2)

우리는 (직장에서) 그 문제를 겪고 여러 달 동안 여러 가지를 시도했습니다. 중첩 된 양식을 올바르게 다루는 방법.

사실, ControlValueAccessor 는 갈 길이 멀지 만 우리는 매우 장황한 것으로 발견되었고 중첩 된 폼을 구축하는 것은 꽤 길었습니다. 앱 내에서 패턴을 많이 사용함에 따라 조사가 끝나고 더 나은 솔루션을 찾기 위해 시간을 투자했습니다. 우리는 이것을 ngx-sub-form 이라고 부르며 NPM ( Github 소스 코드)에서 사용할 수있는 repo입니다.

기본적으로 하위 폼을 만들려면 우리가 제공하는 클래스를 확장하고 FormControl을 전달해야합니다. 그게 전부 야.

우리는 그것을 사용하기 위해 우리의 코드베이스를 업데이트했으며 우리는 확실히 그것에 대해 행복하다. 그래서 당신이 시도하고 그것을 어떻게 당신을 위해 간다 볼 수 있습니다 :)

모든 것은 GithubGithub 설명되어 있습니다.

추신 : 우리는 또한 완전한 데모를 여기 https://cloudnc.github.io/ngx-sub-form 실행하고 있습니다.

중첩 된 양식을 구현하기위한 ControlValueAccessor의 구성은 Angular Connect 2017 프레젠테이션에서 소개됩니다.

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 인스턴스를 중첩 된 폼 구성 요소에 어떻게 든 삽입해야한다고 생각합니다 ...


AppComponent 몇 가지 문제는 FormBuilder 를 다음과 AppComponent 변경합니다.

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







angular