rkmax
rkmax

Reputation: 18125

AngularJS doesn't remove $scope.$on when destroying $scope

I have a simple app built with AngularJS:

var App = angular.module('myApp', [], function($window) {
  // settings..
}).run(function($rootScope){
   $(window).on('resize', function(event) {
        $rootScope.$broadcast('windowResize',{
            height: event.target.innerHeight,
            width: event.target.innerWidth
        });
    });
});

I have a directive, panel, with the following controller:

function($scope, $element) {    
    var
        $title = $element.find('.panel-title'),
        $content = $element.find('.panel-content'),
        margin = 20
    ;
    $content
        .height($(window).height() - $title.height() - margin);

    $scope.$on('windowResize', function(obj) {
        var height = obj.height - $title.height()  - margin;
        $content.height(height);
    });
}

All works perfectly the first time. When the controller changes, however, I get problems like TypeError: Cannot read property '$$childHead' of null, but I can get the error.

The problem is with $scope.$on. How can I remove this before destroying the $scope (when the controller changes)?

Upvotes: 0

Views: 2036

Answers (2)

Orion Edwards
Orion Edwards

Reputation: 123622

You could try hook the $destroy event, and then use .$off

for example:

var onWindowResize = function(obj) {
    var height = obj.height - $title.height()  - margin;
    $content.height(height);
});

$scope.$on('windowResize', onWindowResize);
$scope.$on('$destroy', function(){
    $scope.off('windowResize', onWindowResize);
});

Upvotes: 1

subhaze
subhaze

Reputation: 8855

The $on function returns a deregister function. So you can store that function in a variable and then call the function when you need to deregister the event.

var deregisterWindowResize = $scope.$on('windowResize', function callback(args){...});

$scope.$on('$destory', deregisterWindowResize);

More info here


You could make a function/service if you need to use this often, something like the following would work.

function weakBind(scope, eventName, callback){
    var deregister = scope.$on(eventName, callback);
    scope.$on('$destroy', deregister);
    return deregister;
}

weakBind($scope, 'windowResize', function(obj) {
    var height = obj.height - $title.height()  - margin;
    $content.height(height);
});

Upvotes: 2

Related Questions