user2954587
user2954587

Reputation: 4861

angular 1.5 component initialize on two way binding change

i'm trying to reinitialize a component when a two way bound object changes.

  <ul class="nav nav-pills nav-stacked">
    <li ng-repeat="tab in tabs"
        ng-class="{'active': activeTab.id === tab.id }">
        <a href="" ng-click="setActive(tab)"> {{ tab.title }}</a>
    </li>
  </ul>

  <my-component tab="activeTab"></my-component>


app.component('myComponent', {
  template: '<div>{{ $ctrl.tab.title }}</div>',
  bindings: {
    tab: '='
  },
  controller: function() {
    var init = function() {
      console.log('hi')
    }
    init()
  }
})

How can I make sure init() is called every time activeTab.id changes?

I looked into lifecycle hooks and that doesn't appear to be the answer.

here is a plunkr with code

Upvotes: 1

Views: 3039

Answers (2)

M&#39;sieur Toph&#39;
M&#39;sieur Toph&#39;

Reputation: 2676

You should use the $doCheck method of the component:

function myComponentController(){

  function init() {
    console.log('hi')
  }

  var previousTabId;
  this.$doCheck = function(){
    if (this.tab && previousTabId !== this.tab.id) {
      previousTabId = this.tab.id;
      init();
    }
  }.bind(this);

}

app.component('myComponent', {
  template: '<div>{{ $ctrl.tab.title }}</div>',
  bindings: {
    tab: '='
  },
  controller: [myComponentController]
})

Source : https://docs.angularjs.org/guide/component

$doCheck() - Called on each turn of the digest cycle. Provides an opportunity to detect and act on changes. Any actions that you wish to take in response to the changes that you detect must be invoked from this hook; implementing this has no effect on when $onChanges is called. For example, this hook could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which would not be detected by AngularJS's change detector and thus not trigger $onChanges. This hook is invoked with no arguments; if detecting changes, you must store the previous value(s) for comparison to the current values.


As far as I understand your usecase, you only need a one-way binding. And if you do, you should rather use the $onChanges method (which is reserved to one-way bound properties) :

$onChanges(changesObj) - Called whenever one-way bindings are updated. The changesObj is a hash whose keys are the names of the bound properties that have changed, and the values are an object of the form { currentValue, previousValue, isFirstChange() }. Use this hook to trigger updates within a component such as cloning the bound value to prevent accidental mutation of the outer value.

And you probably should read about $onInit, $onDestroy and $postLink which are really useful too.

Upvotes: 4

rishabh dev
rishabh dev

Reputation: 1743

app.component('myComponent', {
  template: '<div>{{ $ctrl.tab.title }}</div>',
  bindings: {
    tab: '=',
    tabChange:'&'
  },
  controller: function($scope) {
    $scope.$watch(
  function() { return $scope.$ctrl.tab; },
  function(newValue, oldValue) {
    init();
  }
);

var init = function() {
      console.log('hi');
    }
    init()
  }
})

Upvotes: 0

Related Questions