2017-09-25 58 views
1

在Angular 4應用程序的組件中考慮以下簡單示例。它顯示了一個帶有兩個輸入字段的簡單HTML表單。一個輸入字段被直接執行,第二個是一個子組件內:如何在嵌套組件的表單中實現自動錶單驗證?

<form #personForm="ngForm"> 
    <input type="text" required name="firstname [(ngModel)]="firstname"/> 
    <app-smart-input required [(model)]="lastname"></app-smart-input> 
    <button [disabled]="personForm.valid === false">Send</button> 
</form> 

分量被定義爲子如下:

import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; 

@Component({ 
    selector: "app-smart-input", 
    templateUrl: "./smart-input.component.html", 
    styleUrls: ["./smart-input.component.css"] 
}) 
export class SmartInputComponent { 

    //////////////// 
    // PROPERTIES // 
    //////////////// 

    @Input() model: string; 
    @Output() modelChange: EventEmitter<string> = new EventEmitter<string>(); 

    @Input("required") required: boolean = false; 

    ///////////// 
    // METHODS // 
    ///////////// 

    updateChanges() { 
     this.modelChange.emit(this.model); 
    } 

} 

與下面的HTML:

<input type="text" [required]="required" [(ngModel)]="model" (ngModelChange)="updateChanges()" /> 

現在更新模型完全正常(firstnamelastname由用戶輸入按預期定義)。

我想實現的是按鈕被禁用,除非填寫了兩個字段。請注意<input>實現中的required標誌,因此這些值不應爲null/undefined。

但不幸的是,該按鈕現在僅在firstname未定義好的情況下被禁用。但表格並不在乎lastname

我該怎麼做到這一點?

注意:Angular 2 creating reactive forms with nested components是simular,但我使用模板驅動的形式,而不是反應形式。但它可能會以某種方式適應?

回答

2

如果您希望SmartInputComponent作爲Angular Form的一部分參與,則需要實施ControlValueAccessor

這意味着爲您的自定義組件提供一種方法,使其與父窗體之間傳播變化。以下是使用SmartInputComponent作爲基礎的實現。

import { Component, OnInit, Input, Output, EventEmitter, forwardRef } from '@angular/core'; 
import { ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms' 

@Component({ 
    selector: 'app-smart-input', 
    templateUrl: './smart-input.component.html', 
    styleUrls: ['./smart-input.component.css'], 
    providers:[ { 
    provide: NG_VALUE_ACCESSOR, 
    useExisting: forwardRef(() => SmartInputComponent), 
    multi: true 
    }] 
}) 
export class SmartInputComponent implements ControlValueAccessor { 

    @Input() model: any; 

    onChange = (_: any) => {}; 
    onTouched =() => {}; 

    writeValue(obj: any): void { 
    if (obj !== undefined) { 
     this.model = obj; 
    } 
    } 

    registerOnChange(fn: any): void { 
    this.onChange = fn; 
    } 

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

    setDisabledState?(isDisabled: boolean): void { 
    //TODO: enabled/disable your input field if you need to 
    } 

    updateChanges(val) { 
    this.onChange(val); 
    } 

    updateBlur(){ 
    this.onTouched(); 
    } 
} 

用一個模板:

<input type="text" (input)="updateChanges(myTextBox.value)" (blur)="updateBlur()" #myTextBox [value]="model"/> 

然後消耗您的組件時,有它參與的形式,如標準控件(角提供ControlValueAccessor實現你)。

<form #personForm="ngForm"> 
    <input type="text" required name="firstname" [(ngModel)]="firstname" name="firstName" /> 
    <app-smart-input required [(ngModel)]="lastname" name="secondName"></app-smart-input> 
    <button [disabled]="personForm.valid === false">Send</button> 

    {{personForm.value | json}} 

</form> 

如果運行這個表格你會看到personForm現在有兩種捕捉的第一和第二個名稱值。

另請參閱ControlValueAccessor上的Angular文檔