最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to destroy $emit and $broadcast events in AngularJS? - Stack Overflow

programmeradmin0浏览0评论

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 your bodyClick 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
Add a ment  | 

1 Answer 1

Reset to default 3

A few notes about your plunkr:

  1. None of your controllers go out of scope, thus none of them emit $destroy.
  2. You're listening for $destroy but attempting to emit destroy, which isn't the same. Remove the $ from the listener and you'll see the callback running.
  3. Because subController is a child of mainController 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 $destroying 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!

发布评论

评论列表(0)

  1. 暂无评论