Angular $ rootScope $在'被破坏的'控制器继续运行

时间:2016-12-28 16:23:04

标签: javascript angularjs lifecycle watch ng-view

我在index.html中使用ng-view指令设置了我的角度应用程序,其中视图配置了$ routeProvider config,每个视图都有自己的控制器。在一个视图控制器中,我在监听器上监视事件的$ rootScope。$。我希望这个监听器在我改变视图时不再运行,但事实并非如此。即使我已经切换到不再使用该控制器的视图,手表仍会在触发时保持调用代码。

我已经设置了一些测试代码来监听$ 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';
});

2 个答案:

答案 0 :(得分:3)

所以问题完全改变了,因此上下文完全不同,所以我之前的答案不再真正涉及这个问题,除了它的应用方式完全相同。

您可以在与我的答案相同的方面取消注册您的听众。

$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功能后,您的手表将被移除。

答案 1 :(得分:0)

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

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

通过此操作,您可以手动确保在非活动控制器上没有更多活动的$ watchers。