Reputation: 95
I’m adding an event listener on each time I create an angular controller. Each time I leave this page and come back to it, a new event listener gets added cause the constructor is called again.
When this event gets triggered, the same event gets invoked twice, and if I leave and come back, it gets invoked 3 times… etc.. I only want it to always get invoked once.
Here is the code to add the event listener, and the Listener function it calls: (FYI I'm using TypeScript)
In Constructor:
this.$window.addEventListener("message", this.processApi, false);
Function Called:
processApi = (e) => {
this.processApiMessage(e.data);
};
I read that I should call a reference to a function instead of typing out the function itself, so both reference the same instance of a function, but the same event listener is being called multiple times.
When I do developer tools in chrome, and go to EventListners, and go to message section, I see a new Window element every time I hit the constructor. I am able to delete each of the EventListers through developer tools but can't seem to get it to work through code when I do:
this.$window.removeEventListener("message", this.processApi, false);
I found out that if I refresh the page, all the event listeners clear and my one in the constructor is created so it works fine.
I'm using angular, and was using the $location service to navigate to the url that hit my controller, so a quick fix was to replace $location.url("url") to window.location.href("url")
This seems to work cause the page gets refreshed when I navigate to it. I would rather keep the $location for routing, and only have my event listener get hit once even though the angular constructor is hit multiple times.
Upvotes: 0
Views: 661
Reputation: 28757
You need to remove the event listener when the scope is $destroyed
. So, in the controller constructor, you need to inject the $scope
object. And in the constructor, do something like this:
$scope.$on('$destroy', () =>
$window.removeEventListener("message", this.processApi));
To be sure, there are several ways of creating a controller. The most common one (especially if you are using TypeScript) is to create a class for the controller.
I would also consider adding the listener to the rootScope instead of $window, which is more the Angular way of doing things. Putting it all together, it would look like this:
class MyController {
constructor($rootScope, $scope) {
'ngInject';
let unsubscriber = $rootScope.$on('message', this.processApi, false);
$scope.$on('$destroy', () => unsubscriber());
}
...
}
Upvotes: 3