Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you emit event from Controller in one module to Directive Controller in another module?

Tags:

angularjs

I have a controller "MyController" and a directive "MyDirective" in separate modules "app" and "directiveModule" respectively. DirectiveModule has been injected into the angular.module of "app".

The issue I am having is as part of "app", I have a controller that emits an event "TEST" that the controller for the directive does not pick up. How can I successfully get the directive of its own module to catch the emit? Is this possible? (Note: I tried $scope originally, then used $rootScope, but both do not make a difference.)

My controller:

app.controller('MyController', function($scope, $rootScope) {
  $rootScope.$emit('TEST');
});

My directive:

directiveModule.directive('MyDirective', ['$rootScope', 'MyService',
function($rootScope, MyService) {

return {
   restrict: 'E',
   controller: ['$scope', '$rootScope', function($scope, $rootScope) {
        $rootScope.$on('TEST', function() {alert("Event Caught")})

}]};
}];

UPDATE: It looks like my directive has not initiated by the time the event is broadcast. Is there a way to make it such that I could "wait for directive to instantiate" as opposed to waiting an arbitary "1000" ms or another alternative?

like image 773
Rolando Avatar asked Dec 29 '13 02:12

Rolando


3 Answers

I think the only case your directive needs to catch that event is to get some initial data depending on the MyController because if your directive is independent of the MyController, you don't need to catch that event, just initiate the directive independently.

My solution is using $watch to get notified when the initial data from the MyController is ready.

app.controller('MyController', function($scope) {
   $scope.data = {}; //initialize the data, this data could be fetched from an ajax
});

directiveModule.directive('MyDirective', ['MyService',
function(MyService) {

return {
   restrict: 'E',
   controller: ['$scope', function($scope) {
        $scope.$watch("data",function(newValue,OldValue,scope){
             //do your work here when data is changed.
        });  
    }]};
}];

In case you use isolate scope in your directive:

directiveModule.directive('MyDirective', ['MyService',
    function(MyService) {

    return {
       restrict: 'E',
       scope : {
           directiveData:"=", 
       },
       controller: ['$scope', function($scope) {
            $scope.$watch("directiveData",function(newValue,OldValue,scope){//watch on the directive scope property
                 //do your work here when data is changed.
            });  
        }]};
    }];

Your html may look like this:

<my-directive directive-data="data" /> //bind isolate scope directive property with controller's scope property.

I think below questions are some similar cases like this:

  • AngularJS : Directive not able to access isolate scope objects
  • AngularJS : directives and scope
like image 141
Khanh TO Avatar answered Oct 25 '22 00:10

Khanh TO


all modules injected into main module share same rootScope. $emit however travels up the scope tree, you need $broadcast.

If you $broadcast from $rootScope it will be received by all active scopes so in directive could actually use $scope.$on and wouldn't need to inject $rootScope just for the purpose of using $on

Similarly if directive is descendant of the controller, could also broadcast from controller scope

like image 27
charlietfl Avatar answered Oct 24 '22 23:10

charlietfl


You can. Demo: http://plnkr.co/edit/vrZgnu?p=preview

A side note: if you try to communicate to children element that is lower in DOM tree, you should use $broadcast. $emit is used to communicate with parents elements ("up" direction).

But your true problem might be that when you tried to emit the event, the directive might not be initiated yet. I used $timeout service to wait 1000ms to broadcast the event.

Update

If you don't want to wait a arbitrary 1000ms, you can let your directive $emit "ready" event to inform controller that it's ready. Then broadcast from the controller.

Also removed the 1000ms in this demo http://plnkr.co/edit/GwrdIw?p=preview, everything still works. But I don't think this is a reliable solution.

like image 31
Daiwei Avatar answered Oct 25 '22 00:10

Daiwei