此篇文章紀錄一下在自訂的component實做NgModel來Two Way Binding還有Template Driven的驗證做法
前言
雖然組件間的溝通,新的框架都不太支援元件間Two Way Binding的做法,但有時候如果只是一個父子組件,沒有很複雜的tree結構的話,Two Way Binding還是很方便的,那這篇就來把自己研究的成果紀綠下來囉。
實做一個簡單的父子元件
我的目標是想在父元件直接用ngModel來做two way binding加上驗證,所以先加上一個子元件就叫child.component,接著看一下child的部份吧
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from "@angular/forms";
import { Component, OnInit, forwardRef } from '@angular/core';
export const CHILD_ACCESSER: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ChildComponent), //ChildComponent是此component的類別
multi: true
};
@Component({
selector: 'app-child',
template: `
<p>
<input type="text" [(ngModel)]="message">
</p>
`,
providers: [CHILD_ACCESSER]
})
export class ChildComponent implements ControlValueAccessor {
value: string;
get message() { //取得NgModel的值
return this.value;
}
set message(value) { //寫進NgModel的值
this.value = value;
this.notifyValueChange(); //通知父層值已修改
}
notifyValueChange() {
if (this.onChange) {
this.onChange(this.message);
}
}
onChange: (value) => {};
onTouched: () => {};
writeValue(obj: any): void {
this.message = obj;
if (!this.message) {
this.message = null;
}
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
constructor() { }
}
接著再看一下父元件就很簡單了,注意一下name和required是要寫在父元件這層,而不是寫在child這個子元件的input裡面
import { INCREASE_COUNT, REDUCE_COUNT } from './store/action-type';
import { RootState } from './store/root-reducer';
import { Store } from '@ngrx/store';
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { NgForm } from "@angular/forms/src/directives";
@Component({
selector: 'app-root',
template:`
<form #myForm="ngForm" novalidate>
<button (click)="submit(myForm)">submit</button>
<app-child name="message" [(ngModel)]="message" required></app-child>
{{message}}
</form>
`
})
export class AppComponent {
message = "123";
constructor() {
}
submit(myForm:NgForm){
console.log(myForm.value,`isValid:${myForm.valid}`);
}
}
結論
這篇很簡單,主要是紀錄給自己以後備查,也希望對需要的人有點幫助。