将反应式表单拆分成多个组件并进行验证。

问题描述 投票:0回答:1

我们能不能把一个反应式表单分割成多个组件?

例如,父组件中的按钮(SAVE、UPDATE和DELETE)和表单放在子组件中。

如何实现这个功能?

有什么例子吗?

有什么例子吗?

angular angular7 angular8 angular-reactive-forms angular9
1个回答
0
投票

你可以将一个反应式表单分割成多个子表单,但是你需要利用ControlValueAccessor和它的朋友,你需要将它嵌套在一个父表单中,从那里提交。当然,你还需要添加一些额外的模板,以便拥有所有的验证和反应式表单所需要的其他一切。

你可以通过这种方式拥有任意多的子表单。

下面你可以看到一个例子,说明你如何用Angular的方式来实现它。

子组件

import { Component, OnInit, forwardRef } from '@angular/core';
import {
  NG_VALUE_ACCESSOR,
  NG_VALIDATORS,
  ControlValueAccessor,
  Validator,
  FormGroup,
  FormBuilder,
  AbstractControl,
  ValidationErrors,
  Validators
} from '@angular/forms';

@Component({
  ...
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => ChildComponent),
      multi: true
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => ChildComponent),
      multi: true
    }
  ]
})
export class ChildComponent implements OnInit, ControlValueAccessor, Validator {
  public childForm: FormGroup;
  public onTouched: () => void = () => {};

  constructor(private fb: FormBuilder) {}

  ngOnInit(): void {
    this.childForm = this.fb.group({
     ...
    });
  }

  public writeValue(val: any): void {
    return val && this.childForm.setValue(val, { emitEvent: false });
  }

  public registerOnChange(fn: any): void {
    this.childForm.valueChanges.subscribe(fn);
  }

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

  public setDisabledState?(isDisabled: boolean): void {
    isDisabled ? this.childForm.disable() : this.childForm.enable();
  }

  public validate(control: AbstractControl): ValidationErrors | null {
    return this.childForm.valid
      ? null
      : { invalidForm: { valid: false, message: 'Form is invalid' } };
  }
}

子组件模板。

<ng-container [formGroup]="childForm">
.....
</ng-container>

父组件 ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';

@Component({
  ...
})
export class StandardSetupFormComponent implements OnInit {
  parentForm: FormGroup;

  constructor(private fb: FormBuilder) {}

  ngOnInit(): void {
    this.parentForm = this.fb.group({
      child: null,
      ...
    });
  }

 public onSubmit() {
  ...
 }
}

父组件模板。

<form class="form" [formGroup]="parentForm" (ngSubmit)="onSubmit()">

  <app-child formControlName="child"></app-child>

  <button[disabled]="parentForm.invalid">Submit</button>
</form>

如你所见,在父组件中,你需要将子表单作为一个表单控件。

还有其他的方法可以做到这一点。例如通过使用输入,即使它看起来更简单,它也不是正确的方式。

我前段时间看过一篇很好的文章,讲的就是我上面给你展示的内容,但是我现在还找不到。如果找到了我会更新答案的。

喏,这里 是文章,让你对嵌套反应式表单有更好更深的理解。


0
投票

过去我在做这个事情的时候,一般会用服务来管理和发布表单。

@Injectable()
export class MyFormService {
  private _form: FormGroup;
  constructor(private fb: FormBuilder) {
    this.buildForm()
  }

  private buildForm() {
    this._form = this.fb.group({
      // whatever form specifics in here
    })
  }

  get form() {
    return this._form
  }

  // whatever of these you need
  get childForm() {
    return this.form.get('childFormKey')
  }

  // any other appropriate methods or observables exposed
}

父组件。

@Component({
  .. component stuff ..
  providers: [MyFormService] // might as well provide it here to keep it private
})
export class ParentComponent {
  constructor(private formService: MyFormService) {

  }

  onSubmit() {
    const value = this.formService.form.value;
    // do the submit
  }
  // any methods you need

}

子组件:

export class ChildComponent {
  childForm: FormGroup

  constructor(private formService: MyFormService) {
    this.childForm = this.formService.childForm;
    // do whatever else you need for this component
  }
}

这种方法最适用于大的复杂表单,你想把它分解成较小的不太复杂的表单,但这些东西不会有很高的可重用性(尽管你仍然可以用这种方法得到很好的可重用性,如果你设置正确的话)。 它也很适合你想要相同的整体表单,但不同模板的情况。

那些更像 "widget "的东西,而且你打算在许多表单中使用,可能会需要一种不同的方法。

© www.soinside.com 2019 - 2024. All rights reserved.