Richard G
Richard G

Reputation: 5683

Why is binding value not available in controller immediately in angular

I'm trying to bind some values in an angular 1.6 component that should be available to the controller code.

I must be misunderstanding it, but the variables aren't available when the controller runs. The only way I've managed it is by putting a $timeout in to push the code into the next digest cycle.

What am I doing wrong here?

The relevant section is here:

var SelectorCtrl = ['$scope', '$http', '$timeout',
  function ($scope, $http, $timeout) {
    var self = this;
    alert("1: " + self.hierarchyId);

    // I'm not 100% sure why this has to be in the next digest cycle
    $timeout(function(){
      $scope.categories = self.categories;
      alert("2: " + self.hierarchyId);

    });
}

app.component('categorySelector', {
  templateUrl: 'categorySelector.html',
  controller: SelectorCtrl,
  bindings: {
    hierarchyId: "@",
    disabled: "=",
    categories: "=",
    onSelectionChanged: "&"
  }
});

See plunker: https://plnkr.co/edit/8rtDuCawdHaiXzQU5VBR

Upvotes: 6

Views: 1945

Answers (1)

Pankaj Parkar
Pankaj Parkar

Reputation: 136154

This is because of $compileProvider.preAssignBindingsEnabled(flag) introduced in Angular 1.6, you can configure it on config cycle on $compileProvider

If disabled (false), the compiler calls the constructor first before assigning bindings.

The default value is true in Angular 1.5.x but will switch to false in Angular 1.6.x.

You will get all bindings inside $onInit lifecycle event of Angular component, where all the bindings would be available(if binding passed synchronously).

self.$onInit = function() {
  $scope.categories = self.categories;
  alert("2: " + self.hierarchyId);
};

Note: It's bad practice to mix $scope with this. Rather avoid using $scope to make your code Angular 2 migration proof.


If you want binding to be available when controller function instantiate then you could set $compileProvider.preAssignBindingsEnabled(true). Which will make self.categories(bindings) value.

app.config(function($compileProvider){
   $compileProvider.preAssignBindingsEnabled(true)
});

Similar answer


Angular 1.7.x update

As of Angular 1.7.x, the $compileProvider.preAssignBindingsEnabled(flag) is gone, and it is no longer possible to assign bindings before the constructor.

To work around this, you need to define a link function in your directive definition. You can make this function call a method on your controller like this:

app.directive("directive", function() {
  return {
    controller: DirectiveController, // bind controller any way you want
    controllerAs: "ctrl",
    bindToController: true,
    link: function(scope) {
      scope.ctrl.init(); // this will call an init() function on your controller
    }
  }
});

Upvotes: 9

Related Questions