0

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/

2 Answers 2

2

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/

Sign up to request clarification or add additional context in comments.

Comments

0

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.

4 Comments

I would like not to use a setTimeout as it seems a bit hacky.
This seems a bit elaborate for something so trivial? Is there not a more built in way?
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.
I found a more acceptable/correct way of doing it, please see my answer below

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.