1

I'm trying to pass a group of counts as an object through a one way binded variable and am getting an infinite digest because the method I'm binding to the component with is returning a new object every time. Here's the example:

In parent component template:

<some-component counts="$ctrl.selectedCounts()"></some-component>

Parent component definition:

angular.module().component('parentComponent', {
  controller() {
    return {
      selectedCounts() {
        return {
          [this.selectedThing1.length > 1 ? 'thing' : 'things']: this.selectedThing1.length,
          [this.selectedThing2.length > 1 ? 'thing' : 'things']: this.selectedThing2.length,
        }
      }
    }
  }
})

How can I bind this counts binding such that it doesn't create an infinite digest without mutating an object in the parent component and passing that to some-component? I've tried using =* as the binding in some-component and while yes it doesn't create an infinite digest cycle, but it also doesn't propagate changes to the child component then for some reason.

Here's a fiddle that has that same infinite digest: http://jsfiddle.net/joshdmiller/HB7LU/

Jay
  • 998
  • 1
  • 10
  • 22
  • you aren't passing the object to your component here, you are passing the function itself to the component. – Claies Aug 28 '17 at 01:45
  • Oop my bad, I was rewriting the example and missed the `()` – Jay Aug 28 '17 at 01:47
  • Use the [$doCheck Life-Cycle Hook](https://docs.angularjs.org/api/ng/service/$compile#life-cycle-hooks) to perform a deep equality check for changes which would not be detected by AngularJS's change detector and thus not trigger `$onChanges`. If detecting changes, you must store the previous value(s) for comparison to the current values. – georgeawg Aug 28 '17 at 04:32

1 Answers1

1

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
  • I'm confused how this solves the infinite digest cycle, I'm still getting infdigs whenever I have a one way binding. How does the `$doCheck` help with this? I thought this was more "do this thing when you check if you need to update," I could totally be wrong though. Thanks! I really want to get a clean solution to this, I've definitely ran into this before and kind of skirted around the issue. – Jay Aug 28 '17 at 04:45
  • Should I be using the shallow binding of =* instead of < in this case? Just thinking out loud, but that might solve the issue since the doCheck is mostly useful when your component doesn’t properly receive changes, which is what’s happening with =*. – Jay Aug 28 '17 at 04:49
  • Use one-way `<` binding but only change the contents of the object. I need a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) to write a better answer. – georgeawg Aug 28 '17 at 04:59
  • Hm, I see. Sorry about that on a plane right now so don’t have the best wifi haha. I’ll update this q with a more complete example once I land! – Jay Aug 28 '17 at 05:00
  • I added a jsfiddle to the question, hopefully this will help! http://jsfiddle.net/joshdmiller/HB7LU/ – Jay Aug 28 '17 at 19:06