Skip to content

Commit b216a8b

Browse files
authored
Merge pull request angular-ui#273 from ValentinH/fix-dom-markers-leaks
fix(markers): fix dom markers memory leaks
2 parents c30e5d1 + ceb4169 commit b216a8b

File tree

7 files changed

+107
-24
lines changed

7 files changed

+107
-24
lines changed

dist/ui-leaflet.js

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*!
2-
* ui-leaflet 1.0.0 2016-06-13
2+
* ui-leaflet 1.0.0 2016-07-18
33
* ui-leaflet - An AngularJS directive to easily interact with Leaflet maps
44
* git: https://github.com/angular-ui/ui-leaflet
55
*/
@@ -1385,7 +1385,7 @@ angular.module('ui-leaflet').service('leafletIterators', ["leafletLogger", "leaf
13851385
// `key:value` pairs.
13861386
var _matcher,
13871387
_matches = null;
1388-
_matcher = _matches = function _matches(attrs) {
1388+
_matcher = _matches = function (attrs) {
13891389
attrs = _extendOwn({}, attrs);
13901390
return function (obj) {
13911391
return _isMatch(obj, attrs);
@@ -1404,7 +1404,7 @@ angular.module('ui-leaflet').service('leafletIterators', ["leafletLogger", "leaf
14041404

14051405
var _every,
14061406
_all = null;
1407-
_every = _all = function _all(obj, predicate, context) {
1407+
_every = _all = function (obj, predicate, context) {
14081408
predicate = cb(predicate, context);
14091409
var keys = !_isArrayLike(obj) && _keys(obj),
14101410
length = (keys || obj).length;
@@ -2319,10 +2319,12 @@ angular.module('ui-leaflet').service('leafletMarkersHelpers', ["$rootScope", "$t
23192319
if (!DomMarkersPlugin.isLoaded()) {
23202320
$log.error(errorHeader + 'The DomMarkers Plugin is not loaded.');
23212321
}
2322-
var markerScope = angular.isFunction(iconData.getMarkerScope) ? iconData.getMarkerScope() : $rootScope,
2322+
var markerScope = angular.isFunction(iconData.getMarkerScope) ? iconData.getMarkerScope().$new() : $rootScope,
23232323
template = $compile(iconData.template)(markerScope),
23242324
iconDataCopy = angular.copy(iconData);
2325+
iconDataCopy.ngElement = template;
23252326
iconDataCopy.element = template[0];
2327+
if (angular.isFunction(iconData.getMarkerScope)) iconDataCopy.scope = markerScope;
23262328
return new L.DomMarkers.icon(iconDataCopy);
23272329
}
23282330

@@ -2366,8 +2368,23 @@ angular.module('ui-leaflet').service('leafletMarkersHelpers', ["$rootScope", "$t
23662368
}
23672369
};
23682370

2371+
var _cleanDomIcon = function _cleanDomIcon(marker) {
2372+
if (marker.options.icon.options.ngElement) {
2373+
marker.options.icon.options.ngElement.remove();
2374+
}
2375+
if (marker.options.icon.options.scope) {
2376+
marker.options.icon.options.scope.$destroy();
2377+
}
2378+
};
2379+
23692380
var _deleteMarker = function _deleteMarker(marker, map, layers) {
23702381
marker.closePopup();
2382+
2383+
// if it's a dom icon, clean it
2384+
if (marker.options.icon && marker.options.icon.options && marker.options.icon.options.type === 'dom') {
2385+
_cleanDomIcon(marker);
2386+
}
2387+
23712388
// There is no easy way to know if a marker is added to a layer, so we search for it
23722389
// if there are overlays
23732390
if (isDefined(layers) && isDefined(layers.overlays)) {
@@ -2561,6 +2578,10 @@ angular.module('ui-leaflet').service('leafletMarkersHelpers', ["$rootScope", "$t
25612578
if (!isObject(markerData.icon)) {
25622579
// If there is no icon property or it's not an object
25632580
if (isObject(oldMarkerData.icon)) {
2581+
if (oldMarkerData.icon.type === 'dom') {
2582+
// clean previous icon if it's a dom one
2583+
_cleanDomIcon(marker);
2584+
}
25642585
// If there was an icon before restore to the default
25652586
marker.setIcon(createLeafletIcon());
25662587
marker.closePopup();
@@ -2576,6 +2597,10 @@ angular.module('ui-leaflet').service('leafletMarkersHelpers', ["$rootScope", "$t
25762597
if (marker.dragging) {
25772598
dragG = marker.dragging.enabled();
25782599
}
2600+
if (oldMarkerData.icon.type === 'dom') {
2601+
// clean previous icon if it's a dom one
2602+
_cleanDomIcon(marker);
2603+
}
25792604
marker.setIcon(createLeafletIcon(markerData.icon));
25802605
if (dragG) {
25812606
marker.dragging.enable();
@@ -3658,7 +3683,7 @@ angular.module('ui-leaflet').directive('geojson', ["$timeout", "leafletLogger",
36583683
if (angular.isFunction(geojson.onEachFeature)) {
36593684
onEachFeature = geojson.onEachFeature;
36603685
} else {
3661-
onEachFeature = function onEachFeature(feature, layer) {
3686+
onEachFeature = function (feature, layer) {
36623687
if (leafletHelpers.LabelPlugin.isLoaded() && isDefined(feature.properties.description)) {
36633688
layer.bindLabel(feature.properties.description);
36643689
}
@@ -4519,7 +4544,7 @@ angular.module('ui-leaflet').directive('markers', ["leafletLogger", "$rootScope"
45194544
if (isDefined(controller[1])) {
45204545
getLayers = controller[1].getLayers;
45214546
} else {
4522-
getLayers = function getLayers() {
4547+
getLayers = function () {
45234548
var deferred = $q.defer();
45244549
deferred.resolve();
45254550
return deferred.promise;
@@ -4570,6 +4595,9 @@ angular.module('ui-leaflet').directive('markers', ["leafletLogger", "$rootScope"
45704595
if (watchTrap.changeFromDirective) return;
45714596
_create(newMarkers, oldMarkers);
45724597
});
4598+
scope.$on('$destroy', function () {
4599+
_destroy(leafletScope.markers, {}, leafletMarkers, map, layers);
4600+
});
45734601
});
45744602
});
45754603
}
@@ -4643,7 +4671,7 @@ angular.module('ui-leaflet').directive('paths', ["leafletLogger", "$q", "leaflet
46434671
if (isDefined(controller[1])) {
46444672
getLayers = controller[1].getLayers;
46454673
} else {
4646-
getLayers = function getLayers() {
4674+
getLayers = function () {
46474675
var deferred = $q.defer();
46484676
deferred.resolve();
46494677
return deferred.promise;

dist/ui-leaflet.min.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/ui-leaflet.min.no-header.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/ui-leaflet_dev_mapped.js

Lines changed: 35 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/ui-leaflet_dev_mapped.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/directives/markers.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ angular.module('ui-leaflet').directive('markers',
269269
return;
270270
_create(newMarkers, oldMarkers);
271271
});
272+
scope.$on('$destroy', function () {
273+
_destroy(leafletScope.markers, {}, leafletMarkers, map, layers);
274+
});
272275
});
273276
});
274277
}

src/services/leafletMarkersHelpers.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,13 @@ angular.module('ui-leaflet').service('leafletMarkersHelpers', function ($rootSco
7676
if (!DomMarkersPlugin.isLoaded()) {
7777
$log.error(errorHeader + 'The DomMarkers Plugin is not loaded.');
7878
}
79-
var markerScope = angular.isFunction(iconData.getMarkerScope) ? iconData.getMarkerScope() : $rootScope,
79+
var markerScope = angular.isFunction(iconData.getMarkerScope) ? iconData.getMarkerScope().$new() : $rootScope,
8080
template = $compile(iconData.template)(markerScope),
8181
iconDataCopy = angular.copy(iconData);
82+
iconDataCopy.ngElement = template;
8283
iconDataCopy.element = template[0];
84+
if(angular.isFunction(iconData.getMarkerScope))
85+
iconDataCopy.scope = markerScope;
8386
return new L.DomMarkers.icon(iconDataCopy);
8487
}
8588

@@ -123,8 +126,23 @@ angular.module('ui-leaflet').service('leafletMarkersHelpers', function ($rootSco
123126
}
124127
};
125128

129+
var _cleanDomIcon = function _cleanDomIcon(marker) {
130+
if( marker.options.icon.options.ngElement) {
131+
marker.options.icon.options.ngElement.remove();
132+
}
133+
if( marker.options.icon.options.scope) {
134+
marker.options.icon.options.scope.$destroy();
135+
}
136+
};
137+
126138
var _deleteMarker = function (marker, map, layers) {
127139
marker.closePopup();
140+
141+
// if it's a dom icon, clean it
142+
if(marker.options.icon && marker.options.icon.options && marker.options.icon.options.type === 'dom') {
143+
_cleanDomIcon(marker);
144+
}
145+
128146
// There is no easy way to know if a marker is added to a layer, so we search for it
129147
// if there are overlays
130148
if (isDefined(layers) && isDefined(layers.overlays)) {
@@ -319,6 +337,9 @@ angular.module('ui-leaflet').service('leafletMarkersHelpers', function ($rootSco
319337
if (!isObject(markerData.icon)) {
320338
// If there is no icon property or it's not an object
321339
if (isObject(oldMarkerData.icon)) {
340+
if(oldMarkerData.icon.type === 'dom') { // clean previous icon if it's a dom one
341+
_cleanDomIcon(marker);
342+
}
322343
// If there was an icon before restore to the default
323344
marker.setIcon(createLeafletIcon());
324345
marker.closePopup();
@@ -334,6 +355,9 @@ angular.module('ui-leaflet').service('leafletMarkersHelpers', function ($rootSco
334355
if (marker.dragging) {
335356
dragG = marker.dragging.enabled();
336357
}
358+
if(oldMarkerData.icon.type === 'dom') { // clean previous icon if it's a dom one
359+
_cleanDomIcon(marker);
360+
}
337361
marker.setIcon(createLeafletIcon(markerData.icon));
338362
if (dragG) {
339363
marker.dragging.enable();

0 commit comments

Comments
 (0)