【问题标题】:Angular 2: ngOnChanges fires when template rendersAngular 2:模板渲染时触发 ngOnChanges
【发布时间】:2017-06-30 18:41:36
【问题描述】:

当我的模板渲染函数时,ngOnChanges 会触发一次,然后仅在 @input 更改时触发。这是预期的行为,我该如何防止它?

孩子:

export class MobileMenuComponent implements OnInit, OnChanges {

@Input('test') dezeTest: string;

//declare menu
menu;

constructor() { 

    //define menu

    this.menu = {state: 'inactive'};

}

togglemenu() {

    var that = this;

    if (that.menu.state === 'inactive'){

        that.menu.state = 'active';

    }

    else {

        that.menu.state = 'inactive';

    }

}

ngOnChanges(changes: SimpleChanges) {


    this.togglemenu();


}
}

【问题讨论】:

    标签: javascript angular typescript


    【解决方案1】:

    这是 ngOnChanges 的正常行为。

    ngOnChanges 方法将在第一次触发,因为您的属性已被检查,随后会在属性更新时触发。从documentation可以看到

    ngOnChanges 在数据绑定属性被检查之后和视图和内容子元素被检查之前被调用,如果它们中的至少一个发生了变化。

    如果你想改变它,你需要考虑你想如何改变它。你的问题不是很清楚,但是如果你想防止 ngOnChanges 再次触发,当属性被更新时(我认为你想要这个是因为你的 toggleMenu() 你可以考虑使用 ngOnInit() 而不是 @ 987654326@。或者,您可以在第一次之后阻止togglemenu();。

     firstrun : boolean = true; // class variable
     ngOnChanges(changes : SimpleChanges){
        if(firstrun){
          this.togglemenu();
          firstrun = false;
        }
      }
    

    或者,如前所述,另一个lifecycle hook 可能更适合您的需求。

    【讨论】:

    • 谢谢,第二个正是我要找的东西。这个问题背后的故事是,用户应该在一个组件中按下一个按钮,而子组件中需要发生一些事情。如果没有 ngOnChanges,有没有更好的方法来做到这一点?
    • @Dirk 您也可以为此使用响应式扩展。您可以在某处创建一个包含菜单状态的主题(布尔主题,真/假)。当在组件上按下按钮时 - 更改主题的状态。这将创建一个订阅者可以观察到的事件。 (在你的孩子身上,你可以观察这个事件,并适当地处理变化)
    • 好的。有点像带有 observable 的 HTTP 请求。您有什么我可以观看或阅读的内容以了解有关此事的更多信息吗?因为听起来 observables 是更清洁的解决方案。
    • @Dirk 看看这里:angular.io/docs/ts/latest/cookbook/… 这应该可以帮助你:-)
    • 谢谢。这顺便说一句为什么我不会这样做?让那个=这个; let menubutton = document.getElementById('menubutton') let clicks = Observable.fromEvent(menubutton, 'click') clicks.subscribe(click => { that.togglemenu(); });
    【解决方案2】:

    扩展现有答案,同时解决评论中提出的打字问题:

    对于这种情况,存在 SimpleChange#firstChange 字段。

    另外,由于在调用 ngOnChanges 之前在您的组件上设置了值,您还可以检查字段是否已更改,然后检查是否已设置:

    ngOnChanges(changes: { myField: SimpleChange }) {
        if(changes.myField && this.myField){ 
            // do a thing only when 'myField' changes and is not nullish.
        }
        // Or, if you prefer: 
        if(changes.myField && changes.myField.firstChange){ 
            // Do a thing only on the first change of 'myField'.
            // WARNING! If you initialize the value within this class 
            // (e.g. in the constructor)  you can get null values for your first change
        }
    }
    

    另一个小警告:如果您要使用 WebStorm 等工具重命名组件上的“myField”,则 ngOnChanges 方法参数 ({myField: SimpleChange }) 的“myField”将不会更新。这可能会导致一些有趣的组件初始化错误。

    【讨论】:

      【解决方案3】:

      正如 Dylan Meeus 所建议的,这是正常行为。 但我会建议一个不同的解决方案,它利用传递的 SimpleChange 对象。它包含一个previousValue 和一个currentValue.. 最初,previousValue 没有设置。 https://angular.io/docs/ts/latest/api/core/index/SimpleChange-class.html

      ngOnChanges(changes : any){
         if(changes.menu.previousValue){
            this.togglemenu();
         }
      }
      

      此外,请注意 OnChanges,因为它会在每个输入参数上触发...(您将来可能会添加更多)

      【讨论】:

      • 也是一个很好的解决方案。但我遇到了麻烦。当我尝试访问更改的键时,Typescript 给了我一个不退出错误。 “'SimpleChanges'类型上不存在属性'menubutton'。任何”如果我将更改记录到控制台,我会看到它有一个menubutton属性。我在做什么错?编辑:代码似乎在运行。仍然想丢弃 TS 错误。
      • 我明白了,您可以创建 SimpleChanges 的自定义定义,也可以将其定义为任何。 ngOnChanges(更改:任何)
      • 或者你可以使用changes["menubutton"].previousValue而不是changes.menubutton.previousValueSimpleChange 中还有一个方法isFirstChange(),所以你应该使用changes["menubutton"].isFirstChange()
      猜你喜欢
      • 2018-06-21
      • 1970-01-01
      • 2018-02-16
      • 2017-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-15
      • 2018-01-20
      相关资源
      最近更新 更多