如果@Input 正在接收对象,则 ngOnChanges 不会触发

Tam*_*gár 10 angular2-template angular angular6

父组件模板:

<my-component [param]="whatever"></my-component>
Run Code Online (Sandbox Code Playgroud)

父组件代码:

whatever = { value1: 0, value2: 1, value3: 'foo' };
Run Code Online (Sandbox Code Playgroud)

子组件代码:

@Input() public param: any;

ngOnChanges() {
  console.log('Received input: ', param);
}
Run Code Online (Sandbox Code Playgroud)

这不起作用。whatever子组件ngOnChanges不会注意到对 的任何更改,也不会触发。

如果我尝试使用 setter,它也不起作用:

@Input() set param(value) {
  console.log(value);
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试在父组件中运行手动区域更新,它也无济于事。

显然@Input()只能检测对象的结构何时发生变化,而不能检测其值。

那么如何将对象作为@Input()属性传递并让子组件检测值的变化呢?

Con*_*Fan 15

OnChanges生命周期挂钩,当触发@Input属性值的变化。在对象的情况下,该值是对象引用。如果对象引用没有改变,OnChanges则不会触发。

强制更改检测的一种可能技术是在修改属性值后设置新的对象引用:

this.whatever.value1 = 2;
this.whatever.value2 = 3;
this.whatever = Object.assign({}, this.whatever);
Run Code Online (Sandbox Code Playgroud)

ngOnChanges随后的事件处理程序可用于监视的变化:

ngOnChanges(changes: SimpleChanges) {
  for (let propName in changes) {
    let chng = changes[propName];
    let cur = JSON.stringify(chng.currentValue);
    console.log(propName, cur);
  }
}
Run Code Online (Sandbox Code Playgroud)

作为替代方案,如果@Input装饰了 getter/setter 属性,则可以在 setter 中监视更改:

private _param: Object;

@Input() get param(): Object {
  return this._param;
} 
set param(value: Object) {
  console.log("setter", value);
  this._param = value;
}
Run Code Online (Sandbox Code Playgroud)

有关演示,请参阅此 stackblitz

  • 也许添加一个注释来说明为什么创建新对象而不是更改其属性不是一个坏模式是一个好主意。 (2认同)

Fra*_*ous 6

当 @Input 属性值发生变化时,会触发角度变化检测。

因此,要在对象的情况下触发更改检测,您可以使用扩展运算符作为输入来传递对象的副本。

例如。someVar = {key: value}这是@Input()变量,所以像这样传递

<app-sample [someVar]="{...someVar}" ></app-sample>
Run Code Online (Sandbox Code Playgroud)

{...VARIABLE}<-这就是魔法

如果扩展运算符不起作用,请使用任何对象深度复制方法,例如

JSON.parse(JSON.stringify(obj))
Run Code Online (Sandbox Code Playgroud)

  • 角度编译器抛出“意外标记”错误。 (6认同)