Nirav Kamani Nirav Kamani - 3 months ago 85
AngularJS Question

Call function from another controller using Events in AngularJS

I am new bie with AngularJS.

I am trying to call function from another controller.

I found that there are sever ways to do that.

1) Shared Service

2) Using Events

Here is the link that i already checked out.

Can one controller call another

How do I inject a controller into another controller in AngularJS

I think that using events is better approach. Apart from that i think when we use $rootscope it is not destroying event reference right?



var myModule = angular.module('myapp', []);

myModule.controller('otherController', function($scope) {
$scope.$on('ShowDialog', function(event) {
alert("hello");
});
});

myModule.controller('myController', function($scope) {
$scope.OnClick = function() {
alert("Done");
$scope.$emit('ShowDialog');
}
});

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div style="padding: 0 5px; height: 100%" ng-app="myapp">
<div style="padding: 0 5px; height: 100%" ng-controller="myController">
<input type="button" ng-click="OnClick()" value="Say Hello!" />
</div>
</div>





Please let me know what i am missing? And what is the best way to do it?

gyc gyc
Answer

There's a couple reasons why your snippet doesn't work.

You don't instantiate otherController so there's no way it will execute any code at all. So you need to add a div with ng-controller="otherController"

Now that you have an instance of the 2 controllers, to communicate with $scope events ($emit, $broadcast, $on) they need to be nested because scope events depend on the hierarchy of elements.

$scope.$emit will register events to parent controllers.

$scope.$broadcast will register events to child controllers.

You can manipulate the snippet below by moving the nested div out and changing events type.

var myModule = angular.module('myapp', []);

myModule.controller('otherController', function($scope) {
  $scope.$on('ShowDialog', function(event) {
    alert("hello");
  });
});

myModule.controller('myController', function($scope) {
  $scope.OnClick = function() {
    alert("Done");
    $scope.$broadcast('ShowDialog');
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div style="padding: 0 5px; height: 100%" ng-app="myapp">
  <div style="padding: 0 5px; height: 100%" ng-controller="myController">
    <input type="button" ng-click="OnClick()" value="Say Hello!" />
    <div ng-controller="otherController"></div>
  </div>
</div>

If the way your application is built prevents you from nesting controllers, you can use $rootScope events.

They work like this:

$rootScope.$broadcast will broadcast events to the rootScope as well as the scope. This will make your code messy real quick because any scope of any controller can watch for this event.

$rootScope.$emit is to be preferred as it registers the event application wide and makes it available to the rootScope only. ($rootScope.$on)

This said, it is considered bad practice to use $scope or $rootScope events for simple data manipulation that does not make sense application wide.

For example you want to tell your application that user has logged out, then it makes sense to broadcast it to the application as a whole.

But if you just want 1 controller to know some random data has been loaded, then use a service. (ex: the statistics controller doesn't need to know that a user has changed his profile picture)

It's considered bad practice because you will end up with a lot of events registered from different controllers, you will have conflicting event names and eventually it will be very hard to maintain.

If you still want to stick to events, you should remember to unbind them or you will have memory leaks issues and other nasty bugs:

var unbind = $rootScope.$on('logout', function(event, data) {
    console.log('LOGOUT', data);
});
$scope.$on('$destroy', unbind); //when your controller is unloaded, unbind the events
Comments