我正在构建一个离子2应用程序,并构建了一个包含的基本角度2组件
>输入字段
>用于显示输入标题的标签
>用于显示任何验证错误的标签
我将此称为我的输入组件
我有一个页面组件,上面有一个表单,目前有文本输入. 1个常规输入(密码)和1个输入包装在我的输入组件(用户名)中.
这是我的页面组件的相关部分
ngOnInit() { this.loginForm = this.formBuilder.group({ username: ['',Validators.required],password: ['',Validators.required] }); }
这是页面组件模板
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()"> <!-- My input component --> <aw-input-text id="username" name="Username" [formInput]="loginForm.controls.username"></aw-input-text> <!-- A standard input control --> <ion-item [class.error]="loginForm.controls.password.errors"> <ion-label floating>Password</ion-label> <ion-input type="text" value="" name="password" formControlName="password"></ion-input> <p *ngIf="loginForm.controls.password.errors">This field is required!</p> </ion-item> <button type="submit" class="custom-button" [disabled]="!loginForm.valid" block>Login</button> </form>
这是我输入组件的模板
<!-- Component template --> <form [formGroup]="formGroup"> <ion-item> <ion-label floating>{{inputName}}</ion-label> <ion-input type="text" formControlName="inputValue"></ion-input> <p *ngIf="!formGroup.controls.inputValue.valid">This field is required!</p> </ion-item> </form>
这是输入组件
import {Component,Input} from '@angular/core'; import {FormBuilder} from '@angular/forms'; @Component({ selector: 'aw-input-text',templateUrl: 'build/shared/aw-input-text/aw-input-text.html' }) export class AwInputText { @Input('formInput') public formInput; @Input('name') public inputName; public formGroup; constructor(private formBuilder: FormBuilder) { } ngOnInit() { this.formGroup = this.formBuilder.group({ inputValue: this.formInput }); } }
该组件正确呈现.
问题:
组件内部的输入不会更新其所在表单的有效状态.
当我填写用户名时,密码表格变为有效
当我填写密码时,表单的用户名仍然无效
因此,表单可以看到输入组件的有效状态,只是输入组件更改有效状态不会触发表单更新.
可能解决方案1
如本文所述和plunk
https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2
https://plnkr.co/edit/clTbNP7MHBbBbrUp20vr?p=preview
我可以修改我的页面组件来创建一个表单组,其中包含我想在输入组件中使用的每个表单控件的嵌套表单组
ngOnInit() { this.loginForm = this.formBuilder.group({ username: this.formBuilder.group({ username: ['',}),}); }
这个解决方案符合他们添加输入控件数组的文章中的场景,但在我的情况下,我觉得这很麻烦
可能的解决方案2
我考虑的另一个hacky解决方案是使用输入组件中的@output指令触发页面组件上的事件,每当更新输入组件时刷新表单.
更新到输入组件
this.formGroup.controls.inputValue.valueChanges.subscribe(value => { this.formUpdated.emit({ value: value }) });
更新到页面组件
public onUpdated(value){ this.loginForm.updateValueAndValidity(); }
并更新页面组件模板
<aw-input-text id="username" name="Username" (updated)="onUpdated($event)" [formInput]="loginForm.controls.username"></aw-input-text>
这确实给了我所需的功能,但我认为在每个表单页面上都有一个事件处理程序来使输入组件工作似乎有些麻烦.
这个问题
有没有办法让我的组件更新其所在表单的有效状态(请记住,我希望在每种形式中多次重复使用此组件),而无需借助上述解决方案.
解决方法
我们在自定义表单组件中嵌入了所需的自定义输入组件,自定义表单组件使用@ContentChildren来标识和注册所有子自定义输入组件.
这样我们就不必将表单传递给每个输入,并且每个输入都没有乱七八糟的嵌套表单组.
// Each CustomInputText component exposes a FormControl and // a control definition which has additional info about the control @ContentChildren(CustomInputText,{descendants: true}) public customInputComponents: QueryList<CustomInputText>; private initialised; public ngAfterContentChecked() { // Only initialise the form group once if (!this.initialised) { this.initialised = true; this.customInputComponents.forEach((input)=>{ this.formGroup.addControl(input.controlDefinition.id,input.formControl); }); } }