1

I have two pieces of code in two separate Controllers (in two separate JS files); one triggers an Angular $scope.$broadcast event, and the other an $scope.$on listener.

First Controller (file) snippet:

var Controller1 = function($scope) {
    $scope.triggerMyEvent = function(){
        $scope.$broadcast('triggeredEvent');
    }
    $scope.go = function ( path ) {
        $location.path( path );
    };
}

Second Controller (file) snippet:

var Controller2 = function($scope) {
    $scope.$on('triggeredEvent',function(event){
        console.log('found triggered event');
    });
}

The application is wired together as follows:

var app = angular.module("myApp", ["ngRoute"]);
app.config(function($routeProvider) {
   $routeProvider
    .when("/page2", {
        controller : Controller2
        template : "/page2.html"
     })
    .otherwise({
        template : "<p>Error</p>"
    });
});

The first Controller is referenced by a ng-controller directive in the index.html file; and the other file, page2.html listed above is referenced and loaded from actions on the index:

index.html:

<body ng-controller="Controller1">
    <button ng-click="go('/page2.html')">Page 2</button>
</body>

The first time I load up this code the $scope.$broadcast event is triggered and the $scope.$on listener catches it just fine; if I reload it though the $scope.$on listener doesn't catch it. To be clear, on an initial load the event is triggered and caught just fine; so when restart my server and access the page. However if I refresh the page (F5), I believe the event is being fired but not caught. I'm new to working with this so I am presuming a some lack of knowledge however I have read up on $scope/$rootScope and things like $broadcast/$emit/$on. Any help is appreciated. I see a number of articles on related issues; not seeing anything imminently relevant; although I did note this article:

Angular $broadcast only updating after page refresh

AngularJS event-based communication through isolate scope

The most promising references I believe related to Isolate scope but I have not been able to get anything to work yet.

Community
  • 1
  • 1
Gedalya
  • 899
  • 4
  • 16
  • 28
  • We need to see the rest of your code. This is simply not enough information to answer your question. How is `triggerMyEvent` called? Are there any relevant templates to show? Let's see the controller definitions – Pop-A-Stash Feb 14 '17 at 22:21
  • Hi, thanks, I'll try and add more relevant code; however I simply call the function and use console logging (not shown above) to see that it is triggered everytime. – Gedalya Feb 14 '17 at 22:27
  • I updated the code to provide a more complete picture. – Gedalya Feb 16 '17 at 15:11

1 Answers1

1

$broadcast and $on work through the scope hierarchy. $broadcast sends a message down the scope hierarchy toward it's descendants. Any $on listeners must be a descendant of the scope that the message was broadcast from. If you broadcast from the $rootScope, then every scope will be a descendant and every scope will be able to listen to the message. So, one way to ensure that your message is reachable by all scopes is to broadcast it like so:

// just to demostrate. don't put this in a controller
$scope.triggerMyEvent = function(){
    $rootScope.$broadcast('triggeredEvent');  //don't do this in a controller
}

Ideally, you don't want litter root scope with messages. (Actually you should really never do this. It's even worse if you use $rootScope.$on in a controller as it adds and retains a new listener everytime the controller is initialized). To get to the root of your problem(pun intended) you need to pay attention to this hierarchy, as this will affect your listeners.

One example of this hierarchy:

<div ng-controller="ParentCtrl">
  <div ng-controller="ChildCtrl">
  </div>
</div>

<div ng-controller="SiblingCtrl">
</div>

function ParentCtrl($scope) {
  $scope.$broadcast('parentMsg');
}

function ChildCtrl($scope) {
  $scope.$on('parentMsg', function() {
    // will receive message
  });
}

function SiblingCtrl($scope) {
  $scope.$on('parentMsg', function() {
    // will not receive message
  });
}
Pop-A-Stash
  • 6,572
  • 5
  • 28
  • 54
  • 1
    But this might trigger $scope.$on more than one time as a new $rootScope.$broadcast will be created every time that function is called. Ideally making the controller which has the $scope.$broadcast should be a parent class should solve this. – Chait Feb 14 '17 at 22:30
  • In a service, for example, there is no local scope. If you want to broadcast a message, you must use `$rootScope`. But, it should not really be used inside a controller – Pop-A-Stash Feb 14 '17 at 22:38
  • Yup I completely agree. As you suggested we need more information as in where is the function being called from – Chait Feb 14 '17 at 22:40
  • The broadcast is in a Controller. – Gedalya Feb 14 '17 at 22:49
  • Then you shouldn't be using a $rootScope.$broadcast. Just make sure the controller which is sending out the $scope.$broadcast is a parent to the controller which has $scope.$on. This should trigger every time as long the controller is in DOM – Chait Feb 14 '17 at 23:06
  • One more question. are there any state changes when the first broadcast is happening. if So the controller which has $scope.$on might be removed with its respective html and so would not trigger the $scope.$on – Chait Feb 14 '17 at 23:07