Explain Codes LogoExplain Codes Logo

$on and $broadcast in angular

javascript
event-driven-programming
angularjs
best-practices
Alex KataevbyAlex Kataev·Sep 5, 2024
TLDR

Use $on to listen for specific events within AngularJS controllers or services. Use $broadcast to send events to child scopes, creating a channel for components to communicate. Here's a simple example:

// How to say "Hello!" to all of your children in Angular town $scope.$broadcast('greeting', { message: 'Hello!' }); // The children politely responding. Such good manners! $scope.$on('greeting', (event, data) => console.log(`My parent said "${data.message}". How nice.`)); // 'Hello!'

Understanding the scope hierarchy

In AngularJS, the $scope objects exist in a hierarchical structure similar to how a DOM is organized. Navigating these familial relationships becomes essential when dealing with $on, $broadcast, and $emit.

Shouting up (aka $emit) vs shouting Down (aka $broadcast)

$emit sends the event upward ($emit says "Hi, Mom!") through the scope towards the mighty $rootScope, while $broadcast sends the event downward to offspring scopes ($broadcast yells "Kids, dinner's ready!"). Decide between them considering the listeners' location in the hierarchy.

// $emit shouting upwards "Hi, Mom!"... $scope.$emit('callToMom', { message: 'Hi, Mom!' }); // Child scopes listening for dinner call... $scope.$on('callToMom', (event, data) => { ... });

Unique event names: The name game

To avoid an event clash party, always use unique event names. Prefixing event names with a namespace similar to the module or the feature helps a lot.

Events galore? There are other ways...

Services or controller simplification are good alternatives if you're having an eventful day with $broadcast. Events can sometimes give you a hard time debugging. Consider refactoring to use services for a much-shared data fun or for managing states.

Performance quirks and workarounds

Running $broadcast or $emit is like sending Romeo on a journey through the $scope hierarchy, which can be performance-intensive. If you think Romeo is running a lot, you can:

  • Group the messages to Juliet into a single $broadcast
  • Debounce Romeo's runs if he's trying to reach Juliet too often
  • Unload Romeo's baggage by removing unneeded $scope listeners!

Timing is essential

$timeout lets you control the schedule of event broadcasting. Let Romeo rest or delay his messages delivery to Juliet.

// Let Romeo rest before his next run $timeout(function() { $scope.$broadcast('loveLetterToJuliet', { message: 'Miss you!' }); }, 1000);

Clean up? Yes, please!

Listeners should be cleaned up. Especially true for directives or long-lived services to avoid memory leaks:

$scope.$on('$destroy', function() { // Here goes the Cleanup crew... });

Event service: The postmaster

  • A dedicated Postmaster (aka service) can manage letters (aka events) in Angular town.
  • Postmaster uses a Factory or Service method for easier event broadcasting and subscription.
  • Shout out to Dependency Injection! Makes our Postmaster easily testable and our code modular.
app.factory('postMaster', function($rootScope) { return { shoutOut: function(event, letter) { $rootScope.$broadcast(event, letter); }, listen: function(townSquare, event, handler) { townSquare.$on(event, handler); } }; });