0

I have a use-case, where I want to create a directive which does some processing and returns an array to the controller.

My directive looks something like

    angular.module('directives').directive('reuse','testService',function(testService) {
      return { 
         restrict : 'E', 
         replace : true, 
         scope : 
                { elements: '=elements',  
                  callmethod: '&'
                },
         controller: testController,
         templateUrl: '/abc.html'
        };
   }]);

The testController had a method which listens to an event onControllerClick and calls the reference callmethod method.

    $scope.$on('onControllerClick',function() {
       $scope.elements= ['a','b','c'];
       var x = $scope.elements; // reason for this is explained below
       $scope.callmethod(x);
    }

I made a local variable x, because I was not getting the value of elements directly, even when the array is bound bi-directionally.

My invoking of the directive from the html is like

   <div>   
      <reuse elements="elements" callmethod="callmethod(elements)" />
      <button type="button" ng-click="broadcastMethod()" />
   </div>

The controller of this html looks like

    $scope.elements = [];
    $scope.broadcastMethod = function() {
        $scope.$broadcast('onControllerClick');
    };
    $scope.callmethod = function(parameterElement) {
      console.log(parameterElement);
      console.log($scope.elements);
    }

The problem that I am facing with this approach is, whenever I click on the button, for the first time, the value of both parameterElement and $scope.elements is coming as empty array. But when I click on the button for the second time, Both the values are working as expected. What is it that I am missing on the first time?

P.S : I know the obvious and recommended answer is to use a service, but I am looking for a solution without using them.

Suren Srapyan
  • 66,568
  • 14
  • 114
  • 112
Sai Kumar
  • 112
  • 2
  • 11

1 Answers1

0

When using expression & binding, the parsed expression evaluation function accepts a local variables context object:

$scope.$on('onControllerClick',function() {
   $scope.elements= ['a','b','c'];
   var x = $scope.elements; // reason for this is explained below
   //$scope.callmethod(x);
   var locals = {$elements: x};
   $scope.callmethod(locals);
}

Then in the HTML:

<div>   
  <reuse elements="elements" callmethod="parentMethod($elements)"></reuse>
  <button type="button" ng-click="broadcastMethod()" />
</div>

When the directive invokes the $scope.callmethod(locals) function, the Angular Expression defined by the callmethod attribute is evaluated using the parent scope. Any variables defined in the local context object will override parent scope variables.

RECOMMENDED: Prefix local variables with dollar signs $ to distinguish them from parent scope variables.


I was not getting the value of elements directly, even when the array is bound bi-directionally.

This is a common problem when working with expression & binding and two-way = binding in directives with isolate scope. Because bi-directional = binding uses a watcher to transfer values from directive scope to parent scope, there can be a lag. Expressions with expression & binding execute before the two-way binding does the transfer.

Recommended: Avoid two-way = binding. Instead use one-way < binding and expression & binding with local context variables. This will make the transition to Angular 2+ easier and avoid other problems.

Further reading: AngularJs 1.5 - Component does not support Watchers, what is the work around?

Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95