Plnkr example build:
Following the answer here, I created some $broadcast
events to allow actions in the main $scope
to close popovers in sub $scopes
. However I want to make sure I clean up all my events and not have anything lingering that should not.
I have a popover directive, once the popover is activated I send out:
vs.$emit('popoverOpen');
Then in the main app module ($rootScope), I listen for it here:
vs.$on('popoverOpen',function(events,data) {
// if 'popoverOpen' is heard, then activate this function
// which on click $broadcasts out even 'bodyClick'
// but also destroy the 'popoverOpen' event
vs.bodyClick = function() {
$rootScope.$broadcast('bodyClick');
$rootScope.$$listenerCount.popoverOpen=[];
};
});
Back in the popover Directive, here is my bodyClick
listener:
vs.$on('bodyClick', function() {
vs.searchPopoverDisplay = false;
$rootScope.$$listenerCount.bodyClick=[];
});
^ I also have code in there attempting to kill the bodyClick
event, however to no avail :(
As you can see below, I've removed bodyClick
and popoverOpen
from the $$listenerCount
(there was never anything in the $$listener
object.
However the user is still able to access the vs.bodyClick()
function in the main app rootScope, even though popoverOpen
should have been removed.
So on first load:
- If the user clicks around without opening any popover,
bodyClick
is never captured / transmitted - After opening a popover,
bodyClick
is active - If the user clicks on the body, that event is sent out and closes the popover
- However, now even with NO popovers open, if the user clicks on the body that
bodyClick
event keeps getting sent out
How would you properly remove the events after the bodyClick
event has been sent out to close the popover?
UPDATE I also tried this (), but still the bodyClick event keeps getting sent out after the popover is closed and supposedly destroyed.
popoverDirective function still gets called:
vs.$on('bodyClick', function() {
console.log('bodyClick received ...');
console.log($rootScope.$$listener);
console.log($rootScope.$$listenerCount);
vs.searchPopoverDisplay = false;
var unbind = $rootScope.$on('popoverOpen', []);
vs.$on('$destroy', unbind);
// $rootScope.$$listenerCount.bodyClick=[];
});
Plnkr example build: http://plnkr.co/edit/gB7MtVOOHH0FBJYa6P8t?p=preview
Following the answer here, I created some $broadcast
events to allow actions in the main $scope
to close popovers in sub $scopes
. However I want to make sure I clean up all my events and not have anything lingering that should not.
I have a popover directive, once the popover is activated I send out:
vs.$emit('popoverOpen');
Then in the main app module ($rootScope), I listen for it here:
vs.$on('popoverOpen',function(events,data) {
// if 'popoverOpen' is heard, then activate this function
// which on click $broadcasts out even 'bodyClick'
// but also destroy the 'popoverOpen' event
vs.bodyClick = function() {
$rootScope.$broadcast('bodyClick');
$rootScope.$$listenerCount.popoverOpen=[];
};
});
Back in the popover Directive, here is my bodyClick
listener:
vs.$on('bodyClick', function() {
vs.searchPopoverDisplay = false;
$rootScope.$$listenerCount.bodyClick=[];
});
^ I also have code in there attempting to kill the bodyClick
event, however to no avail :(
As you can see below, I've removed bodyClick
and popoverOpen
from the $$listenerCount
(there was never anything in the $$listener
object.
However the user is still able to access the vs.bodyClick()
function in the main app rootScope, even though popoverOpen
should have been removed.
So on first load:
- If the user clicks around without opening any popover,
bodyClick
is never captured / transmitted - After opening a popover,
bodyClick
is active - If the user clicks on the body, that event is sent out and closes the popover
- However, now even with NO popovers open, if the user clicks on the body that
bodyClick
event keeps getting sent out
How would you properly remove the events after the bodyClick
event has been sent out to close the popover?
UPDATE I also tried this (https://github./toddmotto/angularjs-styleguide#publish-and-subscribe-events), but still the bodyClick event keeps getting sent out after the popover is closed and supposedly destroyed.
popoverDirective function still gets called:
vs.$on('bodyClick', function() {
console.log('bodyClick received ...');
console.log($rootScope.$$listener);
console.log($rootScope.$$listenerCount);
vs.searchPopoverDisplay = false;
var unbind = $rootScope.$on('popoverOpen', []);
vs.$on('$destroy', unbind);
// $rootScope.$$listenerCount.bodyClick=[];
});
Share
Improve this question
edited May 23, 2017 at 12:30
CommunityBot
11 silver badge
asked May 15, 2015 at 19:21
Leon GabanLeon Gaban
39.1k122 gold badges349 silver badges550 bronze badges
4
- There is a note on Todd Motto's Angular guide that mentions destroying publish and subscribe events. It might be what you are looking for. github./toddmotto/… – Matthew Green Commented May 15, 2015 at 19:29
-
Thanks! Hmm I tried out his
destroy
code, but didn't work.. had to also fix a syntax error there, but still no luck... added what I tried above. – Leon Gaban Commented May 15, 2015 at 19:35 - Building a plnkr example now plnkr.co/edit/gB7MtVOOHH0FBJYa6P8t?p=preview – Leon Gaban Commented May 15, 2015 at 20:05
-
So, I added a console to your
$destroy
listener in your plunkr and it never gets called. So then I added a$scope.$destroy()
after yourbodyClick
call, and poof! No more alerts. Not sure if it has the desired after effect though... my plunkr – Tony Commented May 15, 2015 at 20:17
1 Answer
Reset to default 3A few notes about your plunkr:
- None of your controllers go out of scope, thus none of them emit
$destroy
. - You're listening for
$destroy
but attempting to emitdestroy
, which isn't the same. Remove the$
from the listener and you'll see the callback running. - Because
subController
is a child ofmainController
destroying main destroys both and stops the button, along with everything else. This behavior is shown in this plunkr.
So in order to get the pseudo-$destroy
to ping, I changed it to listen on just destroy
.
Then, instead of calling your unbind, which wouldn't work in this case as we aren't actually $destroy
ing anything, I simply replaced the bodyClick
function, as it is bound to the <body>
.
$scope.$on('destroy', function() {
$scope.bodyClick = angular.noop();
});
This seems to have the desired effect. Updated Plunkr here.
Update: I discovered why it was indefinitely adding listeners...! The destroy
listener was in the button callback. So each button press would add yet another callback. I moved the destroy
listener outside of the popover
listener. No more memory leaking!