[英]Angular parent to child binding change detection
簡而言之,我有一個可用作文本輸入的組件。 父組件使用@Input
綁定將數據傳遞到此組件。 當通過@Output
綁定觸發change事件時,我將在父組件中執行一些自動驗證。 這是為了刪除錯誤的值,並將其替換為合理的默認值,以獲得更好的用戶體驗。
這是父組件的基本版本
@Component({
selector: 'parent',
template: `
<div>
<child [value]="item.key1"
(valueChange)="onValueChange($event)">
</child>
</div>
`
})
export class Parent {
item = {
key1: 'test value',
key2: 'another test value'
};
onValueChange(newValue) {
// Perform some validation and set default
if (newValue.length > 4) {
newValue = newValue.substring(0, 4);
}
this.item.key1 = newValue;
}
}
和子組件
@Component({
selector: 'child',
template: `
<div>
<input type="text"
[(ngModel)]="value"
(blur)="onBlur($event)" />
</div>
`
})
export class Child {
@Input() value: string;
@Output() valueChange = new EventEmitter();
onBlur() {
this.valueChange.emit(this.value);
}
}
請參閱此處的Plunker示例
我遇到的問題如下:
當在子輸入中輸入一個值並觸發blur
事件時,新值將冒泡到父級並應用驗證-如果驗證導致該值被修改,它將正確冒泡回到該子值-快樂天。
但是,如果前4個字符保持不變,並且添加了其他字符,則blur
處理仍將應用驗證,並且父級的值將正確更新,但子級將保留“無效”值-不再快樂。
因此,在我看來,Angular並未檢測到父母數據中的更改(因為技術上尚未更改,這很公平),因此也沒有將“最新”值發送回給孩子。
我的問題是,即使技術上沒有“更改”,如何從子文本輸入中始終顯示出正確的值呢?
但是,如果前4個字符保持不變,並且添加了其他字符,則模糊處理仍將應用驗證,並且父級的值將正確更新,但子級將保留“無效”值-不再快樂。
因此,在我看來,Angular並未檢測到父母數據中的更改(因為技術上尚未更改,這很公平),因此也沒有將“最新”值發送回給孩子。
正確。 事實是,angular會“緩存”通過value
輸入屬性傳遞的最新值,並且如您所知,如果您不更改前4個字符,就不會真正將新值推入其中。
您可以通過向孩子添加ngOnChanges(changes)
並將更改值記錄到控制台中來進行檢查; 在上述情況下,不會記錄任何內容,因為不會推送任何新的value value
。
您可以通過以下方法克服此問題:
更好的解決方案
@ Jota.Toledo的好評論讓我意識到我的方法雖然在當時對我來說是一種快速的解決方法,但這並不是一個好方法,所以我實際上對我的項目進行了一些更改,這些更改可以為您服務好吧,也遵循他的建議
將“驗證”邏輯委托給子組件
同時將驗證定義保留在父函數中,並將其作為@Input
參數傳遞給@Input
。
這樣我就給父母兩個公共變量
並更改onValueChange
函數以僅更新item.key1,因為它將已經通過驗證。
在子級中,添加一個新的@Input
參數類型( Function
),類型為Function
然后使用該函數在onBlur內部驗證newValue,然后再將值發送給父級。
我覺得我在這里寫的內容可能會“聽起來”有些混亂,因此我添加了要解釋的代碼。
父級
@Component({
selector: 'parent',
template: `
<div>
<p><b>This is the parent component</b></p>
<child [value]="item.key1"
[validation]="validation"
(valueChange)="onValueChange($event)">
</child>
<p><b>Variable Value:</b> {{item | json}} </p>
</div>
`
})
export class Parent {
item = {
key1: 'test value',
key2: 'another test value'
};
validation = (newValue) => {
if (newValue.length > 4) {
newValue = newValue.substring(0, 4);
}
return newValue;
}
onValueChange(newValue) {
this.item.key1 = newValue;
}
}
子級(將模板部分保留,因為它沒有變化)
export class Child {
@Input() value: string;
@Input() validation: Function;
@Output() valueChange = new EventEmitter();
onBlur() {
this.value = this.validation(this.value)
this.valueChange.emit(this.value);
}
}
先前的答案(不是一個好的方法)
過去我也遇到過類似的問題,我解決的方法是清除var,然后在setTimeout
為其指定最終值,而不指定毫秒。
在您的父組件中,它將類似於以下內容:
onValueChange(newValue) {
console.log('Initial: ' + newValue);
if (newValue.length > 4) {
newValue = newValue.substring(0, 4);
}
console.log('Final: ' + newValue);
this.item.key1 = '';
setTimeout(() => {
this.item.key1 = newValue;
});
}
您應該在ParentComponent
上創建一個Subject
:
export class ParentComponent {
parentSubject:Subject<Item> = new Subject();
notifyChildren() {
this.parentSubject.next('new item value');
}
}
將其作為Input()
傳遞給ChildComponent
:
<child [parentSubject]="parentSubject"></child>
最后在ChildComponent
上subscribe
它:
export class ChildComponent {
@Input() parentSubject:Subject<Item>;
ngOnInit() {
this.parentSubject.subscribe(event => {
//do your stuff with the updated value
});
}
您可以使用以下命令在parent.ts中更新onValueChange方法的代碼
onValueChange(newValue) {
this.item.key1 = null;
setTimeout(() => {
console.log('Initial: ' + newValue);
if (newValue.length > 4) {
newValue = newValue.substring(0, 4);
}
console.log('Final: ' + newValue);
this.item.key1 = newValue;
})
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.