【问题标题】:ngOnChanges not firing if an @Input is receiving an object如果@Input 正在接收对象,ngOnChanges 不会触发
【发布时间】:2019-07-29 16:58:04
【问题描述】:

父组件模板:

<my-component [param]="whatever"></my-component>

父组件代码:

whatever = { value1: 0, value2: 1, value3: 'foo' };

子组件代码:

@Input() public param: any;

ngOnChanges() {
  console.log('Received input: ', param);
}

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

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

@Input() set param(value) {
  console.log(value);
}

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

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

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

【问题讨论】:

  • OnChanges 接受一个参数SimpleChanges。您可以在第一个示例中从那里获得新值,而不是从this
  • 谢谢。但是二传手呢?

标签: angular angular6 angular2-template


【解决方案1】:

我使用第二个@input 变量来触发更改检测:

export class MyViewComponent  {
  @Input() triggerChangeDetection: [];
  @Input() data: Data;

查看:

<app-mycomponent [data]="data" [triggerChangeDetection]="triggerChangeDetection"></app-mycomponent >

每次更新我调用的数据对象时:

export class AppComponent{

  public data: Data;

  public triggerChangeDetection: [];

  private triggerChangeDetectionToUpdateComponents() {
    this.triggerChangeDetection = [];
  }

【讨论】:

    【解决方案2】:

    你有 ref https://angular.io/guide/lifecycle-hooks#onchanges

    日志条目显示为 power 属性的字符串值 变化。但是请注意,ngOnChanges() 方法不会捕获 更改为 hero.name。这是因为 Angular 只有在 输入属性的值发生变化。在这种情况下,英雄是 input 属性, hero 属性的值是对 英雄对象。对象引用的值没有改变 它自己的 name 属性已更改。

    【讨论】:

      【解决方案3】:

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

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

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

      <app-sample [someVar]="{...someVar}" ></app-sample>
      

      {...VARIABLE}

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

      JSON.parse(JSON.stringify(obj))
      

      【讨论】:

      • 您能否举例说明您将如何做到这一点。
      • 角度编译器抛出“Unexpected token”错误。
      • 这不起作用。请提供可行的解决方案或解释。我和上面的@Jack 有同样的问题。
      • 谢谢。现在很清楚了。但是,这听起来不是一个好的解决方案,因为每次刷新都会创建对象副本 - 对吗?
      • 在我的情况下 cloneDeep,传播运算符没有工作状态 ={skip:0, filter:{op:'asc', filters:[{field:'demo', value:'123'} ]}, take:1} 这是我的对象,当我在做 state.filter = ; state = _.cloneDeep(state); onchange 没有被触发
      【解决方案4】:

      我根据富兰克林的回答找到了解决方案:

      只需创建一个返回对象副本的方法,例如

      whateverCopy() {
          return {...this.whatever}
      }
      

      然后通过像

      <my-component [param]="whateverCopy"></my-component>
      

      【讨论】:

      • 是的,这是我自己找到的解决方案。
      【解决方案5】:

      OnChanges 生命周期挂钩在 @Input 属性值更改时触发。对于对象,该值是对象引用。如果对象引用没有改变,则不会触发OnChanges

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

      this.whatever.value1 = 2;
      this.whatever.value2 = 3;
      this.whatever = Object.assign({}, this.whatever);
      

      然后可以使用ngOnChanges 事件处理程序来监控更改:

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

      作为替代方案,如果@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;
      }
      

      请参阅this stackblitz 以获取演示。

      【讨论】:

      • 也许添加注释说明为什么创建新对象而不是更改其属性不是一个坏模式是个好主意。
      【解决方案6】:

      像这样:

      @Input() public param: any;
      ngOnChanges(changes: SimpleChanges): void {
          // Do your check here
          console.log(changes.param.previousValue);
      }
      

      使用更改可以访问 previousValue 和 currentValue。

      【讨论】:

      • 谢谢,确实如此,但出于某种超出我的原因,我们的领导禁止使用 ngChanges。这就是我尝试使用 setter 的原因。
      猜你喜欢
      • 2019-04-21
      • 2018-01-20
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 1970-01-01
      • 2023-04-08
      • 2016-04-06
      • 2016-04-20
      相关资源
      最近更新 更多