2017-09-25 2 views
1

Angular 4アプリケーションのコンポーネントで、次の簡単な例を考えてみましょう。 2つの入力フィールドを持つ単純なHTMLフォームを示しています。ネストされたコンポーネントを含むフォームで自動フォーム検証を実装する方法は?

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

次のHTMLで

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); 
    } 

} 

<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> 

次のように子コンポーネントが定義されている:1つの入力フィールドが直接実装され、第二には、子コンポーネントの範囲内でありますモデルを完全に正常に更新する(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

関連する問題