1

Get updated by model but don't update the model. Should I use the $onChanges function

I have a model:

class Model {
  constructor(data) {
    this.data = data;
  }
  getData() {
    return this;
  }
}

2 nested components:

var parentComponent = {
  bindings: {
    vm: '<'
  },
  controller: function() {
    var ctrl = this;
  },
  template: `
    <div>
      <a ui-sref="hello.about" ui-sref-active="active">sub-view</a>
      Parent component<input ng-model="$ctrl.vm.data">
      <ui-view></ui-view>
    </div>
  `
};
var childComponent = {
  bindings: {
    vm: '<'
  },
  template: `
    <div>
      Child component <input ng-model="$ctrl.vm.data">
      <br/>
      Child component copy<input ng-model="$ctrl.vmCopy.data">
      <br/>
      Child component doCheck<input ng-model="$ctrl.vmCheck.data">
      </div>
  `,
  controller: function() {
    var ctrl = this;
    ctrl.$onChanges = function(changes) {
      ctrl.vmCopy = angular.copy(ctrl.vm);
      ctrl.vm = ctrl.vm;
    };
    ctrl.$doCheck = function () {
      var oldVm;
      if (!angular.equals(oldVm, ctrl.vm)) {
        oldVm = angular.copy(ctrl.vm);
        ctrl.vmCheck = oldVm;
        console.log(ctrl)
      }
    }
  }
}

Both get data from resolve:

.config(function($stateProvider) {
    var helloState = {
      name: 'hello',
      url: '/hello',
      resolve: {
        vm: [function() {
          return myModel.getData();
        }]
      },
      component: 'parent'
    }

    var aboutState = {
      name: 'hello.about',
      url: '/about',
      resolve: {
        vm: [function() {
          return myModel.getData();
        }]
      },
      component: 'child'
    }
    $stateProvider.state(helloState);
    $stateProvider.state(aboutState);

  })

I would like my components to be updated when model change or when parent change, but I don't wan't them to update the model.

I thought that was why one way binding '<' stands for.

Here's a fiddle to illustrate what I want to do.

In other word: I would like the child component to be updated on parent changes but don't want the child to update the parent.

You can see in the fiddle that if I bind directly to local scope, child get update from parent but also update the parent

If I copy the binding to local scope, child isn't updating the parent but also doesn't get updated by parent. If

Community
  • 1
  • 1
IsraGab
  • 4,819
  • 3
  • 27
  • 46

1 Answers1

6

With object content — Use the $doCheck Life-cycle Hook1

When binding an object or array reference, the $onChanges hook only executes when the value of the reference changes. To check for changes to the contents of the object or array, use the $doCheck life-cycle hook:

app.component('nvPersonalTodo', {
  bindings: {
    todos: "<"
  },
  controller: function(){
    var vm = this;
    this.$doCheck = function () {
      var oldTodos;
      if (!angular.equals(oldTodos, vm.todos)) {
        oldTodos = angular.copy(vm.todos);
        console.log("new content");          
        //more code here
      };
    }
})

From the Docs:

The controller can provide the following methods that act as life-cycle hooks:

  • $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 Angular'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.

AngularJS Comprehensive Directive API Reference -- Life-cycle hooks

For more information,

Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • In order to have my vm notified, it can works with the $onChange function but I have to remove the copy (Object.assign). I don't want to remove the copy, I do want to work on a copy in the controller. Anyway, your code work because ou remved the copy. I try with copy and it doesn't work. – IsraGab Aug 06 '18 at 15:56
  • The next step is to [create a PLNKR](http://plnkr.co/edit/?p=preview) to reproduce the problem. – georgeawg Aug 06 '18 at 16:02
  • fiddle: https://jsfiddle.net/yvbenitah/1h07t30z/1153/. I also updated my question – IsraGab Aug 06 '18 at 18:30
  • Ok, Seems I misunderstood something. Your solution works. thanks – IsraGab Aug 09 '18 at 12:02