2016-02-24 2 views
17

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

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

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

+0

Быстрая обратная связь: я должен был сделать «angular.copy()» с объектом (не примитивным), когда я изменяю значения, чтобы запускать '$ onChange()' в дочернем компоненте. – Maxence

+0

Попробуйте этот $ doCheck http://www.kristofdegrave.be/2016/07/component-lifecycle-docheck-angular-15x_22.html –

ответ

7

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

Я создал plnkr that demonstrates both usages.

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

1.5.3 еще не выпущен, правда, правда? Я имел в виду 1.5.0, который был единственным в ветви 1.5.x к моменту написания начального вопроса. – leitasat

+0

Приятно знать, так или иначе, спасибо! – leitasat

+2

1.5.3 был выпущен около недели назад. Крюки были введены в этой версии :). – KwintenP

17

По 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' 
    } 
} 
+0

Это действительно хорошее решение, так как вы по существу используете неизменные данные, поэтому он будет работать идеально с флюсом и всем этим. – leitasat

+2

Это хороший способ исправить это. Но это можно сделать лучше. Я написал blogpost с примером о том, как использовать ImmutableJS, чтобы исправить это «чище». http://blog.kwintenp.com/the-onchanges-lifecycle-hook/ – KwintenP

+1

У меня была аналогичная проблема, но поскольку я имел дело с массивом вместо копии, я просто использовал 'Array.slice()', который возвращает копию массива и '$ onChanges' фактически запущены в компоненте. Благодаря! – Nobita

9

Дилинг с $onChanges сложно. Собственно, именно поэтому в версии 1.5.8 они ввели $doCheck, аналогичный Angular 2 ngDoCheck.

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

Для получения более подробной информации см this blog post

0

В основном, $ onChanges угловой триггер Жизненного цикла крюка, когда угловые найти изменение ссылки (а не свойство в измененном объекте), поэтому для того, чтобы ссылаться на $ 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, если вы действительно хотите, чтобы вызвать функцию обратного вызова в каждом цикле переваривать, потому что он не вызывается в каждом цикле $ переваривать независимо от того, какой связывающих изменений или нет.

Смежные вопросы