The number of subscribers grows every time $rootscope.$on is used

I currently have an Angular controller that is quite simple:

angular.controller('appCtrl', function ($scope, $rootScope) {
    $rootscope.$on('channel.message', function () {
      // do something here
    }
}); 

In addition, I have a sidebar on my webpage that directs me to a view associated with the mentioned controller.

The problem arises when each time I click on a link, Angular creates a new instance of the controller. While this is acceptable, I've noticed that the number of subscribers for my 'channel.message' event is continually increasing, which is not ideal.

I am aware that each piece of code simply adds another callback to the queue but I would like to find a way to only have a single subscriber. What are the recommended best practices in this scenario?

Additionally, I'm familiar with using $scope.$on but it's not suitable due to performance implications and the architecture design of the application itself.

Answer №1

Consider implementing a named function to call your event handler, which will execute it and then clean it up. Here is an example (also, ensure that $rootscope is properly spelled as $rootScope):

angular.controller('appCtrl', function ($scope, $rootScope) {
    var cleanUp = $rootScope.$on('channel.message', function () {
        // carry out tasks here
    };

    cleanUp();
});

I encountered a similar issue (with multiple callbacks being added to the queue), and the above method resolved it for me.


On a side note, I recommend formatting your controller in this way:

angular.controller('appCtrl', ['$scope','$rootScope', function($scope, $rootScope) {

}]);

Answer №2

As pointed out by @JoshBeam, the $rootScope.$on() method returns a function that can be used to deregister your listener. Here is an example:

var cleanUp = $rootscope.$on('channel.message', function () {
   // do stuff here
}

The next question is when to trigger this cleanup. Typically, you would want to deregister the listener when the controller is destroyed. Angular provides a convenient way to do this by firing a $destroy event just before tearing down a scope.

$scope.$on('$destroy', function() {
  cleanUp();
};

It's important to note that we are listening for the $destroy event on the $scope (not on $rootScope) in order to capture when the controller is being torn down. Your regular listener can still remain attached to $rootScope.

This pattern is also useful for preventing memory leaks, even if you don't have multiple listeners to worry about.

Answer №3

In my opinion, it would be beneficial to implement an $onRootScope function, which I have detailed in this response:

How can controllers effectively communicate in AngularJS?

This method simplifies the process by handling event handler deregistration automatically, and its usage is straightforward:

$scope.$onRootScope('barEvent', function(){})

Furthermore, it is worth mentioning that recent updates to angular have mitigated concerns regarding performance impacts of broadcasted events.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Encountered an error while trying to access an undefined property in Angular

Trying to perform a basic import, but encountering a significant stack trace issue. Extensive search efforts have been made to address this problem, yet the stack trace lacks sufficient information for resolution. UPDATE: When setting a variable not sour ...

Fill the drop-down menu with the present day's date, month, and year

I'm new to this, so please bear with me. I have some html and jQuery code: $(document).ready(function() { var d = new Date(); var month = d.getMonth() + 1; var year = d.getFullYear(); $("#month").val(month); $("#year").val(year) ...

Effective technique for connecting client-side JavaScript with server-side node.js

I am striving to create a compact website featuring field auto-completion, drawing suggestions from the server's database (utilizing Node.js + MySQL). What approaches can I take to establish client-server communication as the user inputs data into a ...

Copying elements from ng-repeat scope to outside

I am brand new to AngularJS and I've been trying to figure out a solution for quite some time now without any luck. Basically, I have a form where users can add new fields. These fields are then displayed in a list at the bottom using ng-repeat. When ...

Transform Objects Array from AJAX Response into a Distinct JSON Entity

I am encountering a problem with a sample endpoint that is returning [object Object] for JSON data, and I can't figure out why. Mock API Initially, my code was a bit confusing, but fortunately, I found a clearer solution in another answer. functio ...

Trouble with concealing the headers of a table in AngularJs

I am currently working on developing an angular application that displays football scores. Users can select the option for 2015 matches and only view information for games played in that year. However, I'm facing an issue where even when the 2015 chec ...

Display directional arrow on Ext.grid when the page is initially loaded

Displaying a grid with the product ID is our current setup. While the data is sorted according to the product ID, the sort arrow does not display upon page load. I have observed that clicking on the column reveals the arrow. How can we ensure that the so ...

Assigning a value to the ng-model in AngularJs based on the user's selection from a Dropdown Menu

I tried to utilize a drop-down Selection to assign the model of the Search Box based on user selection: ng-model=searchText.$ (For search across Any of the 3 fields) ng-model=searchText.name (For search only on name field) ng-model=searchText.age (For s ...

Changing colors using JavaScript: A step-by-step guide

Hey there! I'm looking to change the color code in this script from $("#Tcounter").css("color","black") which uses the color word "black", to "#317D29". Can someone help me figure out how to do this? <script type="text/javascript"> $(document). ...

Error encountered: When trying to pass an event and two variables, the function e.preventDefault is not recognized as a valid

As a beginner in JS, I thought I had event handlers figured out. After hours of searching for a solution, I'm stuck. I'm trying to create a carousel, and while it mostly works, when I attempt to pass an event handler and two variables from one fu ...

What is the best way to reference the className within nested SCSS when working with Next.js and React.js?

I am working on customizing a navbar that includes a hamburger button. My goal is to change the style, specifically the bar color and the appearance of the hamburger button, upon tapping. I have already attempted using &:active and .activeBar in the SCSS f ...

"Make your slides smooth and responsive with the unslick option in slick

Currently implementing the Slick Slider on a WordPress website. The slider is designed to display 3 columns at a screen size of 1024px and above. When the screen size drops below 1024px, the slider adjusts to show 2 columns, and on mobile devices, it swit ...

Checking for null values using the "and/or" syntax

While reading an article on special events in jQuery, I came across a syntax that was unfamiliar to me: var threshold = data && data.threshold || 1 I have previously encountered the following: var threshold = data.threshold || 1 As far as I kno ...

Issue with VueJS rendering data within a for loop

As a newcomer to VueJS, I appreciate your patience as I navigate through this. Let me provide as much detail as possible. I am currently working on a Vue app that needs to retrieve a response from a server, iterate through the data, and set a Vue data var ...

How to pass an array as parameters in an Angular HTTP GET request to an API

Hey there! I'm relatively new to Angular and I've hit a roadblock. I need to send an array as parameters to a backend API, which specifically expects an array of strings. const params = new HttpParams(); const depKey = ['deploymentInprogre ...

The use of callback functions with Model.findOne() in Mongoose is now deprecated, and will result

Think about this: app.get("/posts/:postId", function(req, res) { const requestedPostId = req.params.postId; Post.findOne({_id: requestedPostId}, function(err, post) { res.render("post", { title: post.title, content ...

What could be causing one of my images to not appear on my Gatsby page?

Hey there, I could use some help with this issue: Recently, I created a website using Gatsby.js and deployed it to my web server (which is running NGINX on Ubuntu 20.04). The site uses Gatsby Image for querying and displaying images, and everything seems t ...

What is the initial Validity setting in Angular?

When working on an Angular project, I encountered an issue where setting $setValidity to false caused some trouble. $scope.form[key].$setValidity("has_already_taken", false); I was unsure of how to reset the validity to true. I attempted using $scope.for ...

What is the best way to conceal a ModalPopupExtender that is integrated into an ASCX user control without triggering a postback, utilizing JavaScript?

I am currently working on an Asp.net application and have encountered an issue with the ModalPopupExtender embedded within an ASCX user control. I am trying to set up a cancel button that will hide the popup without triggering a post back when clicked. He ...

Tips for Removing Copyright on Charts

Check this out : https://jsfiddle.net/oscar11/4qdan7k7/5/ Is there a way to eliminate the phrase JS chart by amCharts? ...