Angular 在父组件嵌套表单中使用子组件表单

Posted

技术标签:

【中文标题】Angular 在父组件嵌套表单中使用子组件表单【英文标题】:Angular Use Child Component Form in Parent Component Nested Form 【发布时间】:2020-04-05 17:10:27 【问题描述】:

将 ChildComponent 表单放入父组件表单的最佳方法是什么?我们使用的是 2019 年最新的 Angular 8。以下方法经研究后无法完全发挥作用。

父组件:

 ngOnInit() 
    this.parentForm = this.fb.group(
       childForm1: etc
    )

子组件:

this.ChildForm = this.formBuilder.group(
  'streetNumber': [null, [Validators.required, Validators.maxLength(32)]],
  'streetType': [null, [Validators.maxLength(8)]],
  'city': [null, [Validators.maxLength(32)]],
  'state': [null, [Validators.maxLength(16)]],
  'postalCode': [null, [Validators.maxLength(16)]],
,  validator: atLeastOneLocationRequired )

方法一:

这个方法,https://itnext.io/partial-reactive-form-with-angular-components-443ca06d8419 经过严格的测试表明 ParentForm 是有效的,即使 Child Form 是无效的。这不应该发生。

ngOnInit() 
  this.parent = this.fb.group(
    fullName: null
  )

formInitialized(name: string, form: FormGroup) 
  this.checkoutForm.setControl(name, form);

方法二:

方法 2 使用 ViewChild,这是一种不好的做法。 https://davembush.github.io/attaching-an-angular-child-component-s-form-to-a-parent/

@ViewChild(ChildComponent) childComponent: ChildComponent;

And now in ngAfterViewInit() we can add the child’s FormGroup as an additional “control” and set the parent FormGroup to the parent control’s FormGroup.

ngAfterViewInit() 
  this.form.addControl('childForm', this.childComponent.form);
  this.childComponent.form.setParent(this.form);

那么 Angular 8 中最好的 Angular 官方实践是什么?

【问题讨论】:

我这里做了详细解答***.com/a/59285337/2398593 嗨 @maxime1992 这些是父子表单,在两个不同的组件中 另外,尽量不用第三方库 “这些是父表单和子表单,在两个不同的组件中”不确定您要实现的目标然后抱歉 @Artportraitdesign1 也对孩子使用相同的形式 [form]="form" angular.io/guide/dynamic-form 【参考方案1】:

我已经根据你的问题创建了小场景。

父组件:

html

<form [formGroup]="form">
  <app-child [form]="form"></app-child>
  <pre>form.value | json</pre>
</form>

TS:

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

@Component(
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
)
export class AppComponent implements OnInit 
  form: FormGroup;
  constructor (private fb: FormBuilder) 

   ngOnInit() 
    this.form = this.fb.group(
      childForm1: '',
      streetNumber: [null, [Validators.required, Validators.maxLength(32)]],
      streetType: [null, [Validators.maxLength(8)]],
      city: [null, [Validators.maxLength(32)]],
      state: [null, [Validators.maxLength(16)]],
      postalCode: [null, [Validators.maxLength(16)]],
    )
  

子组件:

HTML:

<div [formGroup]="form">
  <input formControlName="streetNumber"><br>
  <input formControlName="streetType"><br>
  <input formControlName="city"><br>
  <input formControlName="state"><br>
  <input formControlName="postalCode">
</div>

TS:

import  Component, OnInit, Input  from '@angular/core';
import  FormGroup  from '@angular/forms';

@Component(
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
)
export class ChildComponent implements OnInit 
   @Input() form: FormGroup;
  constructor()  

  ngOnInit() 
  


工作链接:https://stackblitz.com/edit/angular-gjrphg

更新了多个孩子的链接:https://stackblitz.com/edit/angular-svnqfh?file=src/app/app.component.html

【讨论】:

这种相同的模式是否适用于多个子组件表单转到单个父表单? @Artportraitdesign1 是的,请检查更新的链接(我已经更新了答案) 如果您需要将其嵌套得更深怎么办?假设您有一个用于 postalCode 的子组件,但您仍想将其保留在父组件 FormGroup 中? (并且不指定父 FormGroup 例如,如果我将 postalCode 组件添加到 app.component 和 secondChild.component? @Mackelito 如果我的观点正确,那么您需要为孩子创建组并将您想要的值放在该场景中父母和孩子是分开的。 我通过使用 NG_VALUE_ACCESSOR 解决了这个问题。所以现在您只需添加 formControlName 的每个组件,它就会“连接”到表单中...... :)【参考方案2】:

经过多次讨论和反复试验,我的团队确定了几乎是第一种方法,即子组件定义子表单相应的表单组。但是我们没有使用@ViewChild()AfterViewInit 设置表单控件。相反,我们将父表单传递给子组件并让子组件设置链接。这是因为我们有一个子组件,它可能用于许多不同的父组件,并且重复 AfterViewInit sn-p 会很快变老。此外,如果您的父表单包含在 *ngIf-directive 中,则此方法也有效,因为在子组件初始化时而不是之前进行布线(不再需要讨厌的 @ViewChild() set childComponent() 恶作剧)。

<!-- parent form -->
<app-child-form [parent]="form"></app-child-form>
// Child component
@Component(
    selector: 'app-child-form',
    templateUrl: './child-form.component.html',
)
export class ChildComponent 
    @Input()
    parent!: FormGroup;

    form: FormGroup;

    constructor(private fb: FormBuilder) 
        this.form = this.fb.group(
            // ...
        );
    

    ngOnInit() 
        this.parent.addControl('child-form', this.form);
        this.form.setParent(this.parent);
    

【讨论】:

以上是关于Angular 在父组件嵌套表单中使用子组件表单的主要内容,如果未能解决你的问题,请参考以下文章

在父组件中显示来自子组件的按钮的结果 - Angular

Angular2嵌套模板驱动表单

如何从父组件 OnSubmit Angular 4 触发对子组件的验证?

Angular 2:仅当表单数据有效时才将表单数据从子级传递给父级

Angular 2 使用嵌套组件创建反应式表单

Angular 表单:如何动态添加/删除子表单组件