【问题标题】:Angular $rootScope $on listeners in 'destroyed' controller keep running'destroyed' 控制器中的 Angular $rootScope $on 侦听器继续运行
【发布时间】:2016-12-28 16:23:04
【问题描述】:

我在 index.html 中使用 ng-view 指令设置了我的 Angular 应用程序,视图配置了 $routeProvider 配置,每个视图都有自己的控制器。在一个视图控制器中,我有一个 $rootScope.$on 监听器来监视事件。我希望这个监听器在我更改视图时不再运行,但事实并非如此。手表在触发时仍会继续调用代码,即使我切换到不再使用该控制器的视图也是如此。

我已经设置了一些测试代码来监听 $destroy 事件,我可以看到 $destroy 事件正在被触发,但是监听函数仍然运行。我在 watch 函数和 $destroy 事件监听器中都打印了 $scope.$id,我可以看到 ID 匹配。因此,似乎即使在特定范围内发生 $destroy 事件后,其上的 $on 侦听器仍会继续运行。为什么会这样?我的印象是,当导航到不同的视图时,或者在任何情况下控制器被销毁时,它的侦听器都会被清除。

Plnkr:http://plnkr.co/edit/TxssxQJY5PVLTAIAr4xD?p=preview

var animateApp = angular.module('animateApp', ['ngRoute', 'ngAnimate']);

animateApp.config(function($routeProvider) {
    $routeProvider
        .when('/', {
            templateUrl: 'page-home.html',
            controller: 'mainController'
        })
        .when('/about', {
            templateUrl: 'page-about.html',
            controller: 'aboutController'
        })
        .when('/contact', {
            templateUrl: 'page-contact.html',
            controller: 'contactController'
        });

});

angular.module('animateApp').service('service', ['$interval', '$rootScope', service]);
function service ($interval, $rootScope) {
    var service = {};
    service.abc = 1;
        $interval(function() {
        service.abc++;
        $rootScope.$broadcast('service.abc', service.abc);
    }, 500);

    return service;

}


animateApp.controller('mainController', function($scope, $rootScope, service) {
    $scope.pageClass = 'page-home';
    $scope.$on('$destroy', function iVeBeenDismissed() {
                        console.log('goodbye ' + $scope.$id);
      // release resources, cancel request...
    })

    $rootScope.$on('service.abc', function (newval) {
        console.log($scope.$id);
    })
});

animateApp.controller('aboutController', function($scope) {
    $scope.pageClass = 'page-about';
});

animateApp.controller('contactController', function($scope) {
    $scope.pageClass = 'page-contact';
});

【问题讨论】:

标签: javascript angularjs lifecycle watch ng-view


【解决方案1】:

所以问题完全改变了,因此上下文完全不同,所以我之前的答案不再与问题真正相关,只是它的应用方式完全相同。

您可以按照我在下面的回答相同的方式取消注册您的听众。

$rootScope.$on() 返回一个注销函数。

因此,您的mainController 可以重写为:

animateApp.controller('mainController', function($scope, $rootScope, service) {
    $scope.pageClass = 'page-home';
    var unregister = $rootScope.$on('service.abc', function (newval) {
        console.log($scope.$id);
    });
    $scope.$on('$destroy', unregister);
});

以前的答案

当你的控制器的作用域被销毁时,你应该确保你解绑你的手表。

创建手表时,angular 会为您创建的手表返回一个解除绑定函数。这已经很好地覆盖了here

创建对您创建的手表的引用:

var unbinder = $scope.$watch("foo.bar", doStuff);

照样注意你的示波器被毁坏,但在那里打电话给你的unbinder

$scope.$on("$destroy", function(){
    if(typeof unbinder === "function")
        unbinder();
});

一旦你的unbinder函数被调用,你的手表就会被移除。

【讨论】:

  • @dz210 请重新查看我的答案,因为我已更改它以匹配您的更改。以后有问题请更具体。
  • 感谢您的回复,但我的问题是为什么监听器在控制器似乎被破坏后继续运行,所以我不是在寻找解决方案,而是在寻找正在发生的事情的解释。不幸的是,我已经知道如何取消注册听众和手表。我的问题更具理论性,因为我无法在 Angular 文档中找到答案。
  • 然后@dz210 你的答案是$rootScope 对你的整个应用程序是全局的,并且针对$rootScope 注册一个侦听器对你的隔离范围没有绑定,除非你手动这样做。如果您要将侦听器放置在隔离范围内,例如在$scope.$on 中,那么当范围存在时,您的侦听器将被销毁。你的问题并没有说明你想知道为什么比你想知道如何。
【解决方案2】:

您应该在控制器中添加一个$destroy 事件监听器:

    scope.$on('$destroy', function () {
      element.off('blur'); // example
      element = null;
    });

这样,您将手动确保在非活动控制器上不再有活动的 $watchers。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-21
    • 1970-01-01
    • 1970-01-01
    • 2012-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多