parent.component.html
<parent-comp [data]="mydata"> </parent-comp>
parent.component.ts
this.service.abc$
.takeUntil(this.ngUnsubscribe.asObservable())
.subscribe((data: myType[]) => {
this.mydata= data;
});
child.component.ts
@Input data;
下课我有下面的代码
public ngOnChanges() { if (this.data) { console.log(this.data); } }
现在我希望每当我从父组件到子组件的
@Input data
中收到最新数据时,我的ngOnChanges
函数应该触发并在控制台中打印数据。
但不幸的是
ngOnChanges
功能没有再次触发。它只在组件初始化时触发一次
如果有人想要更多详细信息,请告诉我!
谢谢!
鉴于缺乏进一步的信息,我会做出一个有根据的猜测
@Input data
要么是一个数组要么是一个对象。
根据docs,
ngOnChanges
是:
一个生命周期钩子,当一个对象的任何数据绑定属性被调用时 指令更改。
但是它没有说的是how属性应该改变。一般来说,钩子只有在对属性的引用发生变化时才会触发。
考虑以下例子
父组件控制器
mydata = [];
updateMyData(value: any) {
this.mydata.push(value);
}
父组件模板
<app-child [data]="mydata"></app-child>
子组件控制器
@Input() data: any;
ngOnChanges(changes: SimpleChanges) {
console.log(changes);
}
现在您会期望每次在父组件中调用
ngOnChanges
函数时都会触发updateMyData()
。但是对变量 mydata
的引用永远不会改变。所以钩子不会被触发。有多种方法可以强制更改检测器触发挂钩。
方法一: 将
@Input
装饰器绑定到 setter 而不是直接绑定到变量。已经在answer中讨论过。
方法二: 使用扩展语法重新分配父组件中的变量。
父组件控制器
mydata = [];
updateMyData(value: any) {
this.mydata = [...this.mydata, value];
}
您也可以对对象使用相同的方法。
NgOnChanges 只会在原始类型的输入绑定属性更改时触发。这是因为必须更改对数据变量的引用才能注册更改,以便您可以在此生命周期挂钩中获取它。
因此,实现此目的的可能方法是更改“mydata”变量的引用。比如,当 mydata 变量发生变化时,为它分配一个新的引用,
mydata = [...mydata]
如果它是一个数组,或者mydata = {...mydata}
如果它是来自父组件的对象。
感谢大家提供快速有效的解决方案。
我得到了解决方案,它与你们的建议不完全相同。
在父组件中:
**Earlier I was assigning this way**
`this.mydata= data;`
**But now I am assigning in below way:**
`this.mydata= cloneDeep(data);`
注意:
cloneDeep
是从lodash
进口的
可能是你传递的数据。如果它没有改变,那么 ngOnChanges 将不会注册任何更改。这是一个示例,您可以看到一个属性是否多次更改,然后它只会在第一次更新时触发,但如果您重新创建对象,它每次都会更改。 (查看 stackblitz 中的控制台日志)
https://stackblitz.com/edit/angular-ivy-qmb35h?file=src%2Fapp%2Fapp.component.html
你可以像我一样做,每次都重新创建对象来绕过这个,或者更 hacky 的方法可能是保留一个你传递的虚拟“计数”变量,并在每次你想要子组件时递增它注册更改。
您可以使用 setter 和 getter 方法为 @Input 设置角度。 请参考以下几行以供参考:
private _data: any;
@Input()
set data(data) {
this._data = data;
console.log(this._data);
};
仅从 setter 方法,您也可以调用任何其他方法,并且可以从那里运行您想要的任何逻辑。
您还可以在将对象传递给子对象之前在父对象中对对象进行 JSON 字符串化,然后 JSON 将字符串解析为子对象中的原始对象。
您甚至不必解析子项中的字符串。只需将父对象中的对象字符串化,将它与对象一起传递给父 HTML 模板,不要为子对象中的字符串创建
@Input()
。 ngOnChanges
会开火,你可以用传递的对象做一些事情。
我并不是说这是最好的解决方案,只是说这是一个解决方案。使用传播运算符是我使用的解决方案。