通过验证将表单分成多个组件

时间:2017-04-07 05:48:49

标签: angular typescript angular-forms

我想用角度2创建一个大的形状。但是我想用多个组件创建这个形式,如下例所示。

应用组件

<form novalidate #form1="ngForm" [formGroup]="myForm">
<div>
    <address></address>
</div>
<div>
    <input type="text" ngModel required/>
</div>

<input type="submit" [disabled]="!form1.form.valid" > </form>

地址组件

<div>
<input type="text" ngModel required/> </div>

当我使用上面的代码时,它在我需要的浏览器中可见,但是当我删除地址组件中的文本时,未禁用提交按钮。
但是当我删除应用程序组件中输入框中的文本时,该按钮被正确禁用。

4 个答案:

答案 0 :(得分:61)

我会使用一种非常好的反应形式,以及你的评论:

  

这个还有其他简单的例子吗?也许是没有循环的相同例子

我可以举个例子。您需要做的就是嵌套FormGroup并将其传递给孩子。

我们假设您的表单看起来像这样,并且您希望将address formgroup传递给child:

ngOnInit() {
  this.myForm = this.fb.group({
    name: [''],
    address: this.fb.group({ // create nested formgroup to pass to child
      street: [''],
      zip: ['']
    })
  })
}

然后在您的父级中,只需传递嵌套的表单组:

<address [address]="myForm.get('address')"></address>

在您的孩子中,使用@Input作为嵌套表单组:

@Input() address: FormGroup;

在您的模板中使用[formGroup]

<div [formGroup]="address">
  <input formControlName="street">
  <input formControlName="zip">
</div>

如果您不想创建实际的嵌套表单组,则不需要这样做,您可以将父表单传递给子表单,因此如果您的表单如下所示:

this.myForm = this.fb.group({
  name: [''],
  street: [''],
  zip: ['']
})

你可以传递你想要的任何控制。使用与上面相同的示例,我们只想显示streetzip,子组件保持不变,但模板中的子标记将如下所示:

<address [address]="myForm"></address>

这是

第一个选项的

Demo ,这是第二个 Demo

有关嵌套模型驱动表单的更多信息here

答案 1 :(得分:5)

根据我的经验,使用模板驱动的表单很难形成这种表单字段组合。嵌入在地址组件中的字段不会在表单(NgForm.controls对象)中注册,因此在验证表单时不会考虑这些字段。

  • 您可以使用所有验证创建一个ControlValueAccessor组件(接受ngModel属性),但是很难显示验证错误并传播更改(地址被视为具有复杂值的单个表单字段)。 / LI>
  • 您可以将表单引用传递给Address组件并在其中注册您的内部控件,但我还没有尝试过,这似乎是一种奇怪的方法(我还没有在任何地方看到它)。
  • 您可以切换到活动表单(而不是模板驱动),将表单组对象(表示地址)传递到Address组件,并在表单定义中保留验证。您可以在此处查看示例https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2

答案 2 :(得分:3)

也有一种方法可以在模板驱动的表单中执行。 ngModel在每个组件上自动创建一个单独的表单,但是您可以通过将其添加到组件中来注入父组件的表单:

@Component({
viewProviders: [{ provide: ControlContainer, useExisting: NgForm}]
}) export class ChildComponent

不过,您必须确保每个输入都有唯一的名称。因此,如果使用* ngFor调用子组件,则必须将索引(或任何其他唯一标识符)放入名称中,例如:

[name]="'address_' + i"

如果要将表单结构化为FormGroups,请使用ngModelGroup和

viewProviders: [{ provide: ControlContainer, useExisting: NgModelGroup }]

代替ngForm并添加 [ngModelGroup]="yourNameHere" 到包含标签的html子组件中。

答案 3 :(得分:2)

我想分享在我的案例中完成工作的方法。我创建了以下指令:

import { Directive } from '@angular/core';
import { ControlContainer, NgForm } from '@angular/forms';

@Directive({
  selector: '[appUseParentForm]',
  providers: [
    {
      provide: ControlContainer,
      useFactory: function (form: NgForm) {
        return form;
      },
      deps: [NgForm]
    }
  ]
})
export class UseParentFormDirective {
}

现在,如果您在子组件上使用此指令,例如:

<address app-use-parent-form></address>
来自AddressComponent的

控件将添加到form1中。因此,表单有效性还取决于子组件内部的控件状态。

仅使用Angular 6进行检查