Moshe
Moshe

Reputation: 493

google maps infoWindow click event re-renders map-canvas in Meteor

Hey Im trying to use google maps within my MeteorJS project to have google maps display on a map all customers, and then to display an infoWindow when you click on one of the markers.

problem is anytime you click on the marker it re-renders the map from scratch, i know this has to do with the the reactivity of the Session variable being set when the infoWindow is being clicked.

is there any way avoid the map being re-rendered when the session variable is changing?

thanks.

below is the JS and template im using in my project.

 <template name="customers_map">
 {{#constant}}
 <div id="mapWrapper">
    <div id="map-canvas"></div>
 </div>
 {{/constant}}
</template>

the code for making the google maps and markers.

Template.customers_map.rendered = function() {

$("#map-canvas").height("400px");

if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function(p) {
        Session.set("myLat", p.coords.latitude);
        Session.set("myLng", p.coords.longitude);
    });
}

Deps.autorun(function(){

    var mapOptions = {
        center: new google.maps.LatLng(Session.get("myLat"), Session.get("myLng")),
        zoom: 15,
        zoomControl: true,
        zoomControlOptions: {style: google.maps.ZoomControlStyle.SMALL},
        streetViewControl: false,
        mapTypeControl: false,
        scaleControl: true,
        mapTypeId: google.maps.MapTypeId.SMALL
    }

var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);

var infowindow = new google.maps.InfoWindow({
  content: Template.customers_infoWindow()
  });

Customers.find().forEach(function(customer) {

    if (customer.loc != null) {
        var geo = customer.geoLocation();
        var marker = new google.maps.Marker({
            position: new google.maps.LatLng(geo.lat, geo.lng),
            title: customer.name(),
            icon:'http://maps.google.com/mapfiles/ms/icons/green-dot.png'
        });

        marker.setMap(map);

        google.maps.event.addListener(marker, 'click', function() {
            Session.set("customerId", customer._id);
            infowindow.open(map,marker);
        });

    } else {
        console.log(customer.name() + " has no geoLocation");
    };

});

});

};

the infoWindow template

<template name="customers_infoWindow">
    <h1>{{record.name}}</h1>
</template>

and the js for the infoWindow template

Template.customers_infoWindow.record = function() {
  return Customers.findOne({_id: Session.get("customerId")});
}

Upvotes: 0

Views: 839

Answers (2)

puzzle_fuzzle
puzzle_fuzzle

Reputation: 380

If you create a global googlemaps object, you can access its properties from anywhere. This article has a nice example of doing this. The overall gist is:

  1. Create a googlemaps class with an initialize method. At the end of the initialize method, set a session variable for your map's existence. ( Session.set('map', true);)
  2. Call create a googlemap object by calling the googlemap init method from within Template.customers_map.rendered.

Upvotes: 1

richsilv
richsilv

Reputation: 8013

It's a bit difficult to be sure without having a running version in front of me, but I think this is essentially because you have all your code in one big Deps.autorun block. Clicking one of the markers is changing the Session variable customerId, which will cause customers_infoWindow to re-render (as it's clearly a dependency), but I'm sure this is the intended behaviour.

However, since you're declaring var infoWindow in your Deps.autorun block to have an instance of that template as one of its properties, I think that changing customers_infoWindow will actually invalidate the entire Deps.autorun calculation, which means the whole block will be executed again, including the var map = new google.maps.Map(...) line, which will essentially re-render the map (even though it doesn't re-render that actual div element that contains it).

So, I would suggest splitting your code into separate Deps.autorun blocks, and making sure that anything in the same block should be re-run at the same time - clearly, this means that the Google Maps initialisation code and the infoWindow handler should be in separate blocks.

To reiterate, I think that's what's going on, but you'll have to try it and let me know...

Upvotes: 0

Related Questions