Meteor.js and Google Maps

chaosbohne picture chaosbohne · May 26, 2013 · Viewed 12k times · Source

i already included maps api into my project. Now i want to show some markers on my map. I initialse my map in a startup function:

Meteor.startup(function() {
...
var mapOptions = {
  zoom: 8,
  mapTypeId: google.maps.MapTypeId.ROADMAP
};

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

Than i set the center of the map on rendering

Template.mapPostsList.rendered = function() {
var p2 = Session.get('location');

Map.setCenter(new google.maps.LatLng(p2.lat, p2.lng));
var marker = new google.maps.Marker({
    position: new google.maps.LatLng(p2.lat, p2.lng),
    title:'Meine Position'
  });
marker.setMap(Map);   

Till now everything works fine. Despite i have a PostCollection which contains some coordinates for me. I have a publish and subscribefunction. Now i want to show my posts via markers on the map.

My first idea was to do this in my rendered function. The problem is that on initial load no posts are displayed, because my localcollection(clientside) does not contain any posts. It takes some time until posts are loaded from server.

Thats the reason why i tried to build a helperfunction. Because the helper automatically realoads if something within my posts changes.

Template.mapPostsList.helpers({
posts: function() {
   var allPosts = Posts.find();
   allPosts.foreach(function(post) {
      create marker and attach it to the map
      ....
      marker.setMap(Map);
   })

The Problem is now, that my map variable is not defined. Is there a way to define it in global scope? Why can i use my Map variable in my rendered function? Despite i dont like my approach to inject my markers with the helperfunction or is it the usual way?

Can someone give me hint how to accomplish my problem?

Answer

chaosbohne picture chaosbohne · May 28, 2013

As in my questionpost written i needed some help to integrate google maps functionality. The question was not answered until now and i want you to give a short introduction in how to solve this problem.

How to integrate maps into meteor.js/meteorite.js?

At first you have to include the maps script into your head-tag

<head>
  ....
  <title>Meteor and Google</title>
  <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false">   </script>
</head>

Than you should create a maps-Template:

<template name="mapPostsList">
  <div id="map">
    <div id="map-canvas"></div>
  </div>
</template>

In the related js-File you should define a rendered function. When rendered function is invoked you create a map and show a marker on the map. (Dont forget to give you map some css)

Template.mapPostsList.rendered = function() {  
  var mapOptions = {
    zoom: 12,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };

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

  var p2 = Session.get('location');

  map.setCenter(new google.maps.LatLng(p2.lat, p2.lng));
  var marker = new google.maps.Marker({
    position: new google.maps.LatLng(p2.lat, p2.lng),
    title:'Meine Position',
    icon:'http://maps.google.com/mapfiles/ms/icons/blue-dot.png'
  });
  marker.setMap(map);   

  Session.set('map', true);
};

Now the maps-Object gets recreated everytimes the template is rendered. This is not best practice, but it is working. I tried to put the creation in Template.mapPostsList.created-callback but it always fires an offset-width error. Than i set a marker with my position to the map and define a session that my map is initialised.

Well. But now my Session gets initialised on first rendering, thats why i set it to false when my template is destroyed.

Template.mapPostsList.destroyed = function() {
  Session.set('map', false);
};

If you want to fetch your posts to the map you have to define a autorun function.

Deps.autorun(function() {

  var isMap = Session.get('map');
  if(isMap) {
    var allPosts = Posts.find();
    allPosts.forEach(function (post) {
      var marker = new google.maps.Marker({
        position: new google.maps.LatLng(post.location.lat, post.location.lng),
        title: post.title,
        postId: post._id
      });
      marker.setMap(map);
    });    
  }
});

The Deps.autorun function is always fired if content changes. That means if i change my Session related map-variable the autorun gets invoked. If i set it to false i do nothing. Else i fetch all my posts to the map within an forEach. Because of recreating the map on rendering i dont need to check which posts are already marked on the map when my collection changes.

This solution works quite well for me.

I hope i can someone help with this!