Henry Ollarves Henry Ollarves - 12 days ago 5
Javascript Question

Can't remove Google Map Markers when reloading data

I'm a having some trouble with google maps V3 API.

Here's my AngularJS Directive:

;
(function () {
"use strict";

angular.module('LoVendoApp.directives')
.directive('map', ['SimpleRETS', 'InfoWindowService', 'McOptions', 'ModalOptions', '$rootScope', '$parse', '$uibModal', '$timeout', 'SafetyFilter',
function (SimpleRETS, InfoWindowService, McOptions, ModalOptions, $rootScope, $parse, $uibModal, $timeout, SafetyFilter) {
return {
restrict: 'A',
scope: {
requestObj: '='
},
link: function (scope, el, attrs) {
//Creating map instance with GoogleMaps API
var map = new google.maps.Map(el[0], {
center: {
lat: 25.7742700,
lng: -80.1936600
},
zoom: 8
});

//Markers array
var markers = [];
console.log('on init = ', markers.length);

/**
* Creates new google maps
* marker
*
* @param {Object} param
*
*/

function _newGoogleMapsMarker(param) {
var r = new google.maps.Marker({
map: param._map,
position: new google.maps.LatLng(param._lat, param._lng),
title: param._head,
icon: param._icon
});
if (param._data) {
google.maps.event.addListener(r, 'click', function () {
// this -> the marker on which the onclick event is being attached
if (!this.getMap()._infoWindow) {
this.getMap()._infoWindow = new google.maps.InfoWindow();
}
this.getMap()._infoWindow.close();
var content = InfoWindowService.getContent(param._data);

this.getMap()._infoWindow.setContent(content);
//Creates event listener for InfoWindow insances
google.maps.event.addListener(this.getMap()._infoWindow, 'domready', function () {
$("#iw_container")
.off("click")
.on("click", modalListener);
//Opens modal when click is listened
function modalListener() {
var modalOptions = ModalOptions.getHouseDetailOptions(param._data);
var modalInstance = $uibModal.open(modalOptions);
}
});
this.getMap()._infoWindow.open(this.getMap(), this);
});
}
return r;
}
//Handling request with SimpleRETS service factory
scope.$on('loadMap', function () {
SimpleRETS.requestHandler(scope.requestObj).then(dataReceived, dataError);

function dataReceived(res) {
if (markers.length > 0) {
for (var k = 0; k > markers.length; k++) {
markers[k].setMap(null);
console.log('removing! #', k);
}
markers = [];
console.log('removed!');
}
var results = res.filter(SafetyFilter.filterData);
$rootScope.globalHousesData = results;
if (markers.length == 0)
$timeout(loadMarkers(results), 1000);
}

function dataError(error) {
console.log('mapError', error);
}

});
//Randomizes position for matching coordinates
function randomPos() {
return Math.random() * (0.0001 - 0.00005) + 0.00005;
}

function loadMarkers(results) {
// Fetching marker options from service
var options = McOptions.getOptions;
for (var i = 0; i < results.length; i++) {
var marker = _newGoogleMapsMarker({
_map: map,
_icon: 'assets/images/icon.png',
_lat: results[i].geo.lat,
_lng: results[i].geo.lng,
_head: '|' + new google.maps.LatLng(results[i].geo.lat, results[i].geo.lng),
_data: results[i]
});
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers, options);
}
//Initializes event to load m
scope.$broadcast('loadMap');
}
}
}
]);

})();


As you can see I've been going nuts with console.logs to see what is wrong with my logic. It may look a bit overwhelming but I simply have 4 main components or actions. 1st I initialize the map:

var map = new google.maps.Map(el[0], {
center: {
lat: 25.7742700,
lng: -80.1936600
},
zoom: 8
});


The I instantiate a markers array:
var markers = [];


Then I have 2 main functions. One that create new markers:
_newGoogleMapMarkers(param)


This function takes a param object that basically contain the map object, position coordinates, an icon, title and some content that should be available in the InfoWindow. Also, I'm attatching an onClick listener to all InfoWindows to open an external modal in my app.


The other function should be triggered when the markers array is empty and it loads the new data from the external API I'm using (SimpleRETS)


This is all triggered by an event `$scope.$broadcast('loadMap') that is triggered everytime filters are changed, the user interacts with some stuff, etc.

The problem is that even though I am calling the
loadMarkers()
function when the markers array is empty (and after iterating and doing markers[k].setMap(null)), the old markers stay in the map, creating a massive bloab of markers when loading 500 markers with each load. I even tried setting a timeout of 1000ms after the markers array is empty before the next load, to see if it helped in any way, but it doesn't.

So what do you guys think? I'd appreciate any suggestions you might have.

Answer

For anyone that might be having the same problem. If you are using the markerclusterer jQuery Plugin you must markerCluster.clearMarkers(); before emptying the markers array after a new load of markers.

So basically it'll end up looking something like this

if (markerCluster) {
     markerCluster.clearMarkers();
     markers = [];
}

//Load new markers in the markers array
[...]
//Creating Cluster
markerCluster = new MarkerClusterer(map, markers, options);

Then you would do whatever you need to fetch data and replace the markers, since from this point on the map would be clear of markers and clusters.