Подтвердить что ты не робот

Angular 1.5 компонент onChanges не работает

Поскольку у нас есть довольно большое приложение Angular 1.x, мы не можем полностью его обновить до Angular 2, но мне нравится новая архитектура. Версия 1.5 приносит удивительный component в старое приложение. Как все классно, ему не хватает документации, -)

Итак, вот вопрос. У меня есть две строки в определении контроллера:

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

4b9b3361

Ответ 1

Как и в случае с 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' 
  }
}

Ответ 2

Работа с $onChanges сложна. На самом деле, поэтому в версии 1.5.8 они ввели $doCheck, как и для Angular 2 ngDoCheck.

Таким образом вы можете вручную прослушивать изменения внутри прослушиваемого объекта, который не имеет с крюком $onChanges (вызывается только тогда, когда ссылка на объект изменяется). Это то же самое, но он получает вызов для каждого цикла дайджест, позволяя вам проверять изменения вручную (но лучше, чем часы).

Подробнее см. этот пост в блоге

Ответ 3

Насколько я могу судить, как метод $onChanges, так и $onInit должен работать с версией 1.5.3 для AngularJS.

Я создал plnkr, который демонстрирует оба использования.

Он имеет два компонента - внешний и внутренний компонент, где значение привязано от внешнего к внутреннему компоненту с помощью оператора односторонней привязки <. Поле ввода обновляет значение внешнего компонента. На каждом вводе клавиатуры в поле ввода запускается метод $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;
   }
});

Ответ 4

В принципе, $onChanges angular триггер цикла жизненного цикла, когда 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 независимо от какого-либо изменения привязки или нет.