【问题标题】:How to destroy $emit and $broadcast events in AngularJS?如何在 AngularJS 中销毁 $emit 和 $broadcast 事件?
【发布时间】:2015-07-27 20:01:36
【问题描述】:

Plnkr 示例构建:http://plnkr.co/edit/gB7MtVOOHH0FBJYa6P8t?p=preview

Following the answer here,我创建了一些$broadcast 事件以允许主$scope 中的操作关闭子$scopes 中的弹出框。但是我想确保我清理了所有的事件,并且没有任何不应该的东西挥之不去。

我有一个 popover 指令,一旦 popover 被激活,我就会发送出去:

vs.$emit('popoverOpen');

然后在主应用模块($rootScope)中,我在这里监听:

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=[];
    };
});

回到 popover 指令,这里是我的bodyClick 监听器:

vs.$on('bodyClick', function() {
    vs.searchPopoverDisplay = false;
    $rootScope.$$listenerCount.bodyClick=[];
});

^ 我也有代码试图杀死bodyClick 事件,但无济于事:(

如下所示,我已从 $$listenerCount 中删除了 bodyClickpopoverOpen$$listener 对象中从未有任何内容。

但是,即使 popoverOpen 应该已被删除,用户仍然可以访问主应用 rootScope 中的 vs.bodyClick() 函数。


所以在第一次加载时:

  • 如果用户在没有打开任何弹出框的情况下点击周围,bodyClick 永远不会被捕获/传输
  • 打开弹出框后,bodyClick 处于活动状态
  • 如果用户点击正文,则发送该事件并关闭弹出框
  • 但是,现在即使没有打开任何弹出框,如果用户点击正文,bodyClick 事件就会不断发送出去

在发送bodyClick 事件以关闭弹出框后,您将如何正确删除这些事件?


更新 我也试过这个(https://github.com/toddmotto/angularjs-styleguide#publish-and-subscribe-events),但在弹出框关闭并被销毁后,bodyClick 事件仍然不断发送出去。

popoverDirective 函数仍然被调用:

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=[];
});

【问题讨论】:

  • Todd Motto 的 Angular 指南中有一个注释,其中提到了销毁发布和订阅事件。这可能是您正在寻找的。 github.com/toddmotto/…
  • 谢谢!嗯,我尝试了他的destroy 代码,但没有用.. 还必须在那里修复语法错误,但仍然没有运气...添加了我上面尝试的内容。
  • 现在构建一个 plnkr 示例 plnkr.co/edit/gB7MtVOOHH0FBJYa6P8t?p=preview
  • 所以,我在您的 plunkr 中为您的 $destroy 侦听器添加了一个控制台,但它永远不会被调用。所以我在你的bodyClick 电话之后添加了一个$scope.$destroy(),然后噗!没有更多的警报。不确定它是否具有所需的后效...my plunkr

标签: javascript angularjs angularjs-directive angularjs-scope


【解决方案1】:

关于您的 plunkr 的一些注意事项:

  1. 您的控制器都没有超出范围,因此它们都不会发出 $destroy
  2. 您正在收听$destroy 但试图 发出destroy,这是不一样的。删除 $ 从 监听器,你会看到回调正在运行。
  3. 因为subControllermainController 的子级,所以破坏 main 会破坏两者并停止按钮以及其他所有内容。此行为显示在 this plunkr 中。

所以为了让伪$destroy 能够ping,我将其更改为仅在destroy 上监听。

然后,我没有调用你的 unbind,因为我们实际上并没有 $destroying 任何东西,所以我只是替换了 bodyClick 函数,因为它绑定到 <body>

$scope.$on('destroy', function() {
  $scope.bodyClick = angular.noop();
});

这似乎达到了预期的效果。 更新 Plunkr here.

更新:我发现了为什么它会无限期地添加听众......! destroy 监听器是按钮回调。因此,每次按下按钮都会添加另一个回调。我将destroy 侦听器移到popover 侦听器之外。不再有内存泄漏!

【讨论】:

  • 哦,这就是我想要做的,你如何真正破坏范围?谢谢你的第一部分。我想阻止一个函数被调用,但我也不想再调用不需要的事件。
  • 简单:$scope.$destroy();
  • 是的,我一直在考虑这个 plunkr 很多。我认为它的结构使得真正给你一个可靠的答案变得非常困难。例如,您在我们试图解除绑定的回调中设置了$scope 函数,这实际上不会取消设置该变量,因此该方法仍然存在。希望这可以将您推向正确的方向。
  • 谢谢,是的,现在我正在查看您的 plnkr,当用户单击按钮时,警报永远不会回来。警报只发生一次,但它应该在每次单击按钮时发出警报,而不是在身体的其余部分。我会玩这个...谢谢!
  • @LeonGaban 我在 plunkr 中发现了主要问题。我已经更新了链接。问题是我们在按钮按下的回调中监听了我们的销毁。哇!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-21
相关资源
最近更新 更多