Search code examples
angularjsmemory-leaksleafletevent-listenerangular-leaflet-directive

AngularJS Leaflet memory leak


There is a clear memory leak in my Angular app wherever I use the following leaflet directive: https://github.com/tombatossals/angular-leaflet-directive.

Note that the directive works fine, however the memory footprint continues growing as I leave and return to any view using the directive.

The directive builds off of the leaflet javascript library found here: https://github.com/Leaflet/Leaflet

I use the directive as follows:

<div ng-controller="Explore">
    <div leaflet defaults="defaults" center="center" markers="markers" layers="layers"></div>
</div>

Inside my controller I extend the leaflet directive attributes to the scope:

    angular.extend($scope, {
    defaults: {
        dragging: true,
        doubleClickZoom: false,
        scrollWheelZoom: false,
        maxZoom: 12,
        minZoom: 12
    },
    center: {
        lat: $scope.cities[$scope.market.city][1],
        lng: $scope.cities[$scope.market.city][0],
        zoom: 12
    },
    markers: {},
    layers: {
        baselayers: {
            google: {
                name: 'Google Streets',
                layerType: 'ROADMAP',
                type: 'google'
            }
        }
    }
});

I am not sure what is causing the memory leak, but I believe it may have to do with event listeners that are not removed when $destroy is called within the leaflet directive:

scope.$on('$destroy', function () {
    leafletData.unresolveMap(attrs.id);
});

On destroy the function unresolveMap is called:

this.unresolveMap = function (scopeId) {
    var id = leafletHelpers.obtainEffectiveMapId(maps, scopeId);
    maps[id] = undefined;
};

This is as far as I got. If anyone has come across anything similar or has any ideas as to how to attack this issue further I would greatly appreciate it :)


Solution

  • You should try to remove completly the map by adding a map.remove() in the on $destroy handler (From leaflet API it should: "Destroys the map and clears all related event listeners").

    scope.$on('$destroy', function () {
            leafletData.unresolveMap(attrs.id);
            map.remove();
          });