I have a AngularJs directive that creates a property and callback function on its isolated scope:

.directive('testButton', [function () {
  return {
    restrict: 'A',
    controller: 'TestDirectiveController as vmDirective',
    scope: {     
        myCallBack:'&myCallBack',
        myVariable: '=myVariable'
    },
    template: function (element, attrs) {
        return '<button data-ng-click="vmDirective.onButtonClicked(2)">Set myVariable = 2</button>';
    }
};}])

In the directive a button gets clicked and it executes the onButtonClicked function. This then sets a scope variable and calls the $scope.myCallBack function.

The callBack function gets executed and does the following: console.log($scope.linkedVariable);

The problem is the $scope.linkedVariable has not yet been updated and at that stage the $scope.linkedVariable is still the previous value.

When I wrap the above code in a setTimeout the correct value is retrieved: setTimeout(function(){console.log($scope.linkedVariable)}, 2000);

My Question is, how to properly pass the value to the onCallBack function.

Please see full code example below:

   angular.module('application',[])

   .directive('testButton', [function () {
      return {
         restrict: 'A',
         controller: 'TestDirectiveController as vmDirective',
         scope: {     
              myCallBack:'&myCallBack',
              myVariable: '=myVariable'
         },
         template: function (element, attrs) {
            return '<button data-ng-click="vmDirective.onButtonClicked(2)">Set myVariable = 2</button>';
         }
       };
    }])

  .controller("TestDirectiveController", ['$scope', function($scope){
       var self = this;
       self.onButtonClicked = function(value){
          $scope.myVariable = value;
          $scope.myCallBack();
       };
   }])

  .controller("TestController", ['$scope', function($scope){
      var self = this;
      $scope.linkedVariable = null;

      self.onCallBack = function(){
      console.log($scope.linkedVariable);
      setTimeout(function(){console.log($scope.linkedVariable)}, 2000);
    };
 }])

HTML:

<div data-ng-controller="TestController as vm">
   <div data-test-button="" data-my-call-back="vm.onCallBack()" data-my-variable="linkedVariable"></div>
</div>

jsfiddle: http://jsfiddle.net/ff5ck0da/1/

share|improve this question
up vote 2 down vote accepted

I found a more acceptable/correct way of overcoming my problem thanks to http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-3-isolate-scope-and-function-parameters.

Instead of accessing the $scope.linkedVariable in the controller, I now accept the value as a parameter to the function.

To get this to work I had to change the function declaration in the HTML to:

data-my-call-back="vm.onCallBack"

The controller function declaration:

self.onCallBack = function(myVariable){
    console.log(myVariable);        
};

the directive can then call the function like:

self.onButtonClicked = function(value){        
    $scope.myCallBack()(value);
};

Please see a updated JSFiddle: http://jsfiddle.net/ff5ck0da/9/

share|improve this answer

You can even change the settimeout to

setTimeout(function(){console.log($scope.linkedVariable)}, 0);

this will push the resolution of the variable to the bottom of the async stack. And thus evaluate after the angular digest loop is done ( in essence the variable value is set)

If you dont want to use settimeout you can use this:

self.onCallBack = function(){
        var accessor = $parse($scope.linkedVariable);
        $scope.value = angular.copy(accessor($scope.$parent));
        console.log($scope.linkedVariable);
};

here you are essentially telling angular to not use a copy but the actual parent variable.

share|improve this answer
    
I would like not to use a setTimeout as it seems a bit hacky. – Tjaart van der Walt Jul 2 '15 at 10:23
    
@TjaartvanderWalt I agree see my updated answer – Arno_Geismar Jul 2 '15 at 10:30
    
This seems a bit elaborate for something so trivial? Is there not a more built in way? – Tjaart van der Walt Jul 2 '15 at 10:36
    
I am afraid not. As long as you stay in your directive controller all is wel. But angular starts to make copies between controllers and those need a digest cycle to update. your callback is being triggered before that is done so your variable is not set at that point. the timeout hack forces it to be evaluated last after the digest is done. and the second workaround uses the same variable instead of a copy to circumvent the digest. – Arno_Geismar Jul 2 '15 at 10:44
    
I found a more acceptable/correct way of doing it, please see my answer below – Tjaart van der Walt Jul 2 '15 at 11:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.