【问题标题】:Angular 1.5 component onChanges is not workingAngular 1.5 组件 onChanges 不起作用
【发布时间】:2016-06-06 21:44:55
【问题描述】:

由于我们有相当大的 Angular 1.x 应用程序,我们无法将其完全升级到 Angular 2,但我喜欢新架构。 1.5 版为旧的同一个应用程序带来了惊人的components。和所有很酷的东西一样,它缺少文档 ;-)

所以,这里有一个问题。我在控制器的定义中有这两行:

this.$onInit = setType;
this.$onChanges = setType;

第一个有效,而第二个无效。我正在使用'<' 绑定。因此,在第一次加载时,组件的状态是根据传递的值设置的,而不会反映更改。我希望它应该从 [1] 和 [2] 开始工作。

[1]https://docs.angularjs.org/guide/component

[2]https://angular.io/docs/js/latest/api/core/OnChanges-interface.html

UPD 好的,我知道它不应该工作: https://github.com/angular/angular.js/issues/14030

有人知道好的解决方法吗?

UPD2 从 1.5.3 开始工作

【问题讨论】:

  • 快速反馈:当我修改值以在子组件中触发$onChange() 时,我必须使用对象(非原始)执行angular.copy()
  • 试试这个 $doCheck kristofdegrave.be/2016/07/…

标签: javascript angularjs


【解决方案1】:

处理$onChanges 很棘手。实际上,这就是为什么他们在 1.5.8 版本中引入了$doCheck,类似于 Angular 2 ngDoCheck。

这样,您可以手动监听被监听对象内部的变化,而 $onChanges 钩子不会发生变化(仅当引用对象已更改)。它是同样的东西,但它会在每个摘要周期被调用,允许您手动检查更改(但比监视更好)。

【讨论】:

    【解决方案2】:

    基本上,$onChanges 角度生命周期钩子在 Angular 找到引用中的更改(而不是更改对象中的属性)时触发,因此为了在子项中调用 $onChanges,在父项中分配新对象。例如,

    angular.module("app", [])
    .component("outer", {
        restrict: "E", 
        controller : function(){
            this.value = {};
            this.userButtonClick = function(someValue){
                this.value = angular.copy(someValue);
            }
        },
        template: `<input ng-click="$ctrl.userButtonClick({somevalue : "value"})" /> 
       <br /> 
                <inner value="$ctrl.value">
                </inner>`
        })           
    .component("inner", {
            restrict: "E", 
            template: `{{$ctrl.value}}`, 
            bindings: {
               value: "<"
            },
            controller: function(){
               function setType() { 
                  console.log("called");
               }
               this.$onInit = setType;
               this.$onChanges = function(changeObj){
                   console.log("changed value",changeObj.value.currentValue);
               }
           }
        });
    

    除非你真的想在每个摘要循环中触发回调,否则不要使用 $doCheck,因为无论绑定是否更改,它都会在每个 $digest 循环中调用。

    【讨论】:

      【解决方案3】:

      据我所知,$onChanges$onInit 方法都应该适用于 AngularJS 版本 1.5.3。

      我创建了一个plnkr that demonstrates both usages

      它有两个组件,一个外部组件和一个内部组件,其中使用单向绑定运算符&lt; 将一个值从外部组件绑定到内部组件。输入字段更新外部组件的值。在输入字段中的每次键盘输入时,都会触发 $onChanges 方法(打开控制台查看)。

      angular.module("app", [])
      .component("outer", {
          restrict: "E", 
          template: `<input ng-model=$ctrl.value> <br /> 
                  <inner value="$ctrl.value">
                  </inner>`
      })  
      .component("inner", {
          restrict: "E", 
          template: `{{$ctrl.value}}`, 
          bindings: {
             value: "<"
          },
          controller: function(){
             function setType() { 
                console.log("called");
             }
             this.$onInit = setType;
             this.$onChanges = setType;
         }
      });
      

      【讨论】:

      • 1.5.3 还没有发布,不是吗?我指的是 1.5.0,在编写初始问题时,它是 1.5.x 分支中唯一的一个。
      • 1.5.3 大约在一周前发布。钩子是在那个版本中引入的:)。
      • 如果您使用单向绑定传递对象,并且父组件仅更改对象上的简单属性,是否可能不会触发 $onChanges 事件?看到这支笔:codepen.io/vandenbusschebr/pen/MyrjOa
      • @KwintenP 哦,我的错,分辨率是硬编码的,所以 bower 没有更新 :-) 非常感谢!
      • 我已经写了一篇关于这个主题的博文,提出了一种使用 ImmutableJS 来解决这个问题的方法。你可以在这里查看:blog.kwintenp.com/the-onchanges-lifecycle-hook@BramVandenbussche
      【解决方案4】:

      从 AngularJs 1.5.3 开始,假设 ctrl.someModel 在子组件中是单向绑定的,以下不会触发 $onChanges。

      function get() { 
        api.getData().then( (data) => {
          ctrl.someModel.data = data
        }
      }
      

      似乎更新对象的属性不会被识别为更新。

      这就是我目前解决它的方式。我不认为这是最好的解决方案,但它会触发 $onChanges。我创建了初始模型的深层副本,将数据添加为其属性之一,然后将初始模型设置为新对象的值。本质上,我更新了由生命周期钩子获取的整个对象:

      function get() { 
        api.getData().then( (data='42') => {
          const updatedModel = angular.copy(ctrl.someModel)
          updatedModel.data = data
          ctrl.someModel = updatedModel
        }
      }
      

      并且在子组件中(假设模型被绑定为“数据”):

      this.$onInit = function(bindings) {
        if (bindings.data && bindings.data.currentValue) {
          console.log(bindings.data.currentValue) // '42' 
        }
      }
      

      【讨论】:

      • 这实际上是一个很好的解决方案,因为您本质上使用的是不可变数据,因此它可以完美地处理通量和所有这些东西。
      • 这是解决此问题的好方法。但它可以做得更好。我写了一篇博文,其中有一个关于如何使用 ImmutableJS 以“更清洁”的方式解决此问题的示例。 blog.kwintenp.com/the-onchanges-lifecycle-hook
      • 我遇到了类似的问题,但由于我处理的是数组而不是副本,因此我只使用了Array.slice(),它返回了数组的副本,而$onChanges 实际上是在组件中触发的。谢谢!
      猜你喜欢
      • 1970-01-01
      • 2017-12-20
      • 2016-07-21
      • 2017-06-15
      • 2016-12-01
      • 2019-01-24
      • 1970-01-01
      • 2017-09-28
      • 2017-06-05
      相关资源
      最近更新 更多