[英]angular 2 model driven nested form components
我有什么:
我正在構建一個 ionic 2 應用程序並構建了一個基本的 angular 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: ['', Validators.required],
}),
password: ['', Validators.required],
});
}
此解決方案適合文章中添加輸入控件數組的場景,但就我而言,我認為這感覺很糟糕
可能的解決方案 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);
});
}
}
您可以@Input
您的loginForm
到嵌套組件中,比如parentForm
。 然后在子組件初始化時將嵌套的formGroup
注冊到parentForm
,並在子組件銷毀時取消注冊。
我在我的案例中所做的(嵌套動態形式也是如此)在某種程度上類似於 Marcin 的響應。
我將現有的FormGroup
作為parentForm
傳遞,我的Component
的視圖如下所示:
<fieldset [formGroup]="parentForm">
<label *ngIf="label" [attr.for]="key">{{label}}</label>
<input [id]="key" [type]="type" [formControlName]="key" />
</fieldset>
它適合我的需求。 希望它也能幫到你。
更新:我創建了一個用於加速動態表單創建的庫。 您可以看看我如何使用這個答案中的技術: https : //www.npmjs.com/package/dorf
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.