Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Directive to Directive Communication in AngularJS

So I have this filter directive:

app.directive('filter', function(){
  return {
    restrict: 'E',
    transclude: true,
    scope: {
        callFunc: '&'
    },
    template:
            '   <div>' +
            '       <div ng-transclude></div>' +
            '   </div>',
    controller: function($scope, $element, $attrs){
        this.getData = function() {
            $scope.callFunc()
        }
    }
  }   
});

app.directive('positions', function(){
  return {
    require: '^filter', 
    scope: {
        selectedPos: '='
    },
    template:
            '  Positions: {{selectedPos}}' +
            '  <ul>' +
            '   <li ng-repeat="pos in positions">' +
            '           <a href="#" ng-click="setPosition(pos); posRegData()">{{pos.name}}</a></a>' +
            '       </li>' +
            '  </ul>',
    controller: function($scope, $element, $attrs){
          $scope.positions = [
            {name: '1'},
            {name: '2'},
            {name: '3'},
            {name: '4'},
            {name: '5'}
          ];
          $scope.selectedPos = $scope.positions[0].name;
          $scope.setPosition = function(pos){
            $scope.selectedPos = pos.name;
          };

    },
    link: function(scope, element, attrs, filterCtrl) {
        scope.posRegData = function() {
            filterCtrl.getData();
        }
    }
  }   
})

And the controller:

app.controller('keyCtrl', ['$scope', function($scope) {
  var key = this;
  key.callFunc = function() {
    key.value = key.selectedPos;
    console.log(key.selectedPos)
  }
}]);

The main question is why the key.selectedPos in the controller get's the right value only on the second click?

Here is a plunker replicating my issue.


One way of doing it is to send a param when calling callFunc()

Then, I update the func in the ctrl: key.callFunc = function(filterParams), but also, I am updating the passed method call-func="key.callFunc(filterParams)

Then in filter directive I change getData method to:

this.getData = function(val) {
  $scope.callFunc({filterParams: val})
}

In positions directive I pass the value that I need:

scope.posRegData = function() {
  filterCtrl.getData({position: scope.selectedPos});
}

Finally, in keyCtrl I get the value like this:

key.callFunc = function(filterParams) {
  key.value = filterParams.position;
  console.log(filterPrams.position)
}

Here is a plunker demonstrating this attempt.

The question in this case is if this is a good way of doing it, keeping in mind it's within a very large application.

like image 303
Razvan B. Avatar asked Feb 02 '26 18:02

Razvan B.


1 Answers

That's because how isolated scopes work. The parent scope (the controller in your case) will be updated when the digest cycle runs, which is after your ng-click function called the callFunc. So you can put your callFunc code in a $timeout and it will work (but will cause another digest cycle).

Another solution will be to put the value in an object, so when you change the object the controller (which have the reference) will see the update immediately:

In the controller:

key.selectedPos = { value: {}};

key.callFunc = function() {
    key.value = key.selectedPos.value;  
    console.log(key.selectedPos.value)
} 

In the directive:

$scope.selectedPos.value = $scope.positions[0].name;
$scope.setPosition = function(pos){
    $scope.selectedPos.value = pos.name;
};

See this plunker.

like image 131
eladcon Avatar answered Feb 04 '26 16:02

eladcon



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!