Angularjs directive binding update delay

782 Views Asked by At

I have a problem with directive binding. On the moment when ng-change fires in the event handler I have correct value in ng-model prop but the next line is a call to method binded from controller and in controller handler property which is binded to directive have previous value - it updates one moment later. I'm guessing it is because of digest loop execution steps. Is there a way to have same value on directive and on controller at this moment? Plunker example. One of the solution is to wrap directive event handler code into setTimeout. Is there any other, more 'angular' ways to handle this correctly?

My html:

<text-box textvalue="vm.userInput" loadvalue="vm.onLoadValue()"></text-box>

controller:

angular.module("app").controller("mainController", function(){
  var that = this;
  that.onLoadValue = function(){
    console.log(this.userInput);
  }
});

directive:

angular.module("app").directive("textBox", function(){
  return {
    restriction: "E",
    template: `<input ng-model="textvalue", ng-change="vm.onChange()"/>`,
    scope: {
      textvalue: "=",
      loadvalue: "&"
    },
    controllerAs: "vm",
    controller: function($scope){
      var that = this;
      that.onChange = function(){
        console.log($scope.textvalue);
        $scope.loadvalue();
      }
    }
  }
})
2

There are 2 best solutions below

0
BąQ On

Instead of passing loadvalue method to the directive you can watch variable. Working example

angular.module("app").controller("mainController", function($scope){
  var that = this;
  that.text="test text";

  $scope.$watch("vm.userInput", function(newValue){
    that.tempValue = newValue;
    console.log(newValue);
  });
});
0
georgeawg On

Provide the value as a local in the loadvalue expression:

angular.module("app").directive("textBox", function(){
  return {
    restriction: "E",
    template: `<input ng-model="textvalue", ng-change="vm.onChange()"/>`,
    scope: {
      textvalue: "=",
      loadvalue: "&"
    },
    controllerAs: "vm",
    controller: function($scope){
      var that = this;
      that.onChange = function(){
        console.log($scope.textvalue);
        ̶$̶s̶c̶o̶p̶e̶.̶l̶o̶a̶d̶v̶a̶l̶u̶e̶(̶)̶;̶
        $scope.loadvalue({$value: $scope.textvalue});
      }
    }
  }
})

Usage:

<text-box textvalue="vm.userInput" loadvalue="vm.onLoadValue($value)"></text-box>

The $value local furnished the Angular expression will be the current value without the delay of a digest cycle.