AngularJS
Web Development
JavaScript
Programming
Event Handling

Working with $scope.$emit and $scope.$on

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In AngularJS, $scope.$emit and $scope.$on let scopes communicate through the scope hierarchy. They are useful when a child scope needs to notify a parent scope about something that happened, but they only make sense if you understand the event direction and remember to clean up listeners when scopes are destroyed.

What $emit Actually Does

$emit sends an event upward through parent scopes.

javascript
1app.controller("ChildCtrl", function ($scope) {
2  $scope.save = function () {
3    $scope.$emit("profile:saved", { id: 42 });
4  };
5});

That event starts on the current scope and bubbles upward toward the root scope. Parent scopes can react to it with $on.

javascript
1app.controller("ParentCtrl", function ($scope) {
2  $scope.$on("profile:saved", function (event, data) {
3    console.log("saved profile", data.id);
4  });
5});

This is useful when child controllers or directives need to notify a broader context without directly reaching into parent implementation details.

$on Registers A Listener

$scope.$on listens for events on that scope.

javascript
var deregister = $scope.$on("profile:saved", function (event, data) {
  console.log(data);
});

The important detail is that $on returns a deregistration function. If the listener outlives the scope that should own it, you risk memory leaks or unexpected repeated behavior.

Upward Versus Downward Event Flow

AngularJS has two different scope event directions:

  • '$emit goes upward to parent scopes'
  • '$broadcast goes downward to child scopes'

That distinction is often the real source of bugs. If the code expects children to hear something, $emit is the wrong tool.

The Event Object Matters

The first callback parameter is the AngularJS event object.

javascript
1$scope.$on("profile:saved", function (event, data) {
2  console.log(event.name);
3  console.log(data.id);
4});

The event object contains metadata and also allows propagation control.

javascript
event.stopPropagation();

That can be useful when several ancestor scopes listen for the same event but you want handling to stop after one scope reacts.

Clean Up Long-Lived Listeners

If the listener is attached to $rootScope or another long-lived scope, always keep the deregistration function and call it during cleanup.

javascript
1app.controller("ExampleCtrl", function ($scope, $rootScope) {
2  var deregister = $rootScope.$on("app:refresh", function () {
3    console.log("refresh triggered");
4  });
5
6  $scope.$on("$destroy", deregister);
7});

This pattern is important because $rootScope listeners can survive long after the controller that created them disappears.

When To Use A Service Instead

Scope events are convenient, but they are not always the best architecture. For unrelated controllers or for complex application state, a shared service is often easier to reason about.

Use scope events when the communication is genuinely hierarchical. Use a service when the data is shared state rather than a one-time notification.

That distinction keeps AngularJS code from turning into a web of hidden event dependencies.

Use scope events when the communication is genuinely hierarchical. Use a service when the data is shared state rather than a one-time notification.

That distinction keeps AngularJS code from turning into a web of hidden event dependencies.

$rootScope Is Stronger But Riskier

Events sent through $rootScope can reach much more of the application, which makes them tempting for global notifications. They are useful in moderation, but they also make flow harder to follow because any part of the app can start depending on a string event name that has no explicit import or type contract.

Common Pitfalls

The most common mistake is using $emit when the intended listeners are child scopes rather than parent scopes. Another is attaching listeners to $rootScope and never deregistering them. Developers also often use scope events for ordinary shared state when a service would be clearer and easier to test. Finally, event names should be specific enough to avoid collisions in large applications.

Summary

  • '$scope.$emit sends an event upward through parent scopes.'
  • '$scope.$on registers a listener and returns a deregistration function.'
  • Use $broadcast instead if the event should travel downward.
  • Clean up long-lived listeners, especially those attached to $rootScope.
  • Prefer services over scope events when the real problem is shared application state rather than hierarchical notification.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.