Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait for binding in Angular 1.5 component (without $scope.$watch)

I'm writing an Angular 1.5 directive and I'm running into an obnoxious issue with trying to manipulate bound data before it exists.

Here's my code:

app.component('formSelector', {
  bindings: {
    forms: '='
  },
  controller: function(FormSvc) {

    var ctrl = this
    this.favorites = []

    FormSvc.GetFavorites()
    .then(function(results) {
    ctrl.favorites = results
    for (var i = 0; i < ctrl.favorites.length; i++) {
      for (var j = 0; j < ctrl.forms.length; j++) {
          if (ctrl.favorites[i].id == ctrl.newForms[j].id) ctrl.forms[j].favorite = true
      }
     }
    })
}
...

As you can see, I'm making an AJAX call to get favorites and then checking it against my bound list of forms.

The problem is, the promise is being fulfilled even before the binding is populated... so that by the time I run the loop, ctrl.forms is still undefined!

Without using a $scope.$watch (which is part of the appeal of 1.5 components) how do I wait for the binding to be completed?

like image 818
tcmoore Avatar asked Feb 25 '16 22:02

tcmoore


2 Answers

I had a similar issue, I did this to avoid calling the component until the value I am going to send is ready:

<form-selector ng-if="asyncValue" forms="asyncValue" ></form-selector>
like image 137
Ced Avatar answered Oct 15 '22 08:10

Ced


You could use the new lifecycle hooks, specifically $onChanges, to detect the first change of a binding by calling the isFirstChange method. Read more about this here.

Here's an example:

<div ng-app="app" ng-controller="MyCtrl as $ctrl">
  <my-component binding="$ctrl.binding"></my-component>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.js"></script>
<script>
  angular
    .module('app', [])
    .controller('MyCtrl', function($timeout) {
      $timeout(() => {
        this.binding = 'first value';
      }, 750);

      $timeout(() => {
        this.binding = 'second value';
      }, 1500);
    })
    .component('myComponent', {
      bindings: {
        binding: '<'
      },
      controller: function() {
        // Use es6 destructuring to extract exactly what we need
        this.$onChanges = function({binding}) {
          if (angular.isDefined(binding)) {
            console.log({
              currentValue: binding.currentValue, 
              isFirstChange: binding.isFirstChange()
            });
          }
        }
      }
    });
</script>
like image 28
Cosmin Ababei Avatar answered Oct 15 '22 08:10

Cosmin Ababei