Search code examples
google-mapsbackbone.jsgoogle-maps-api-3

Google Map not rendering correctly after first view with Backbone.js


Im creating a mobile app with Phonegap, Backbone.js, Require.js and PageSlider (https://github.com/ccoenraets/PageSlider).

I want to display a simple Google Map with a marker. The template looks like:

<div class='main-content' id='map-container'>

    <a href="geo:51.903679,-8.468274">
        <div id="map-canvas"></div>
    </a>

</div>

Here is the view:

define(function (require) {

"use strict";

var $                   = require('jquery'),
    _                   = require('underscore'),
    Backbone            = require('backbone'),
    tpl                 = require('text!tpl/Map.html'),
    side_nav                = require('text!tpl/SideNav.html'),
    template = _.template(tpl),
    map, myLatlng, mapOptions, marker;


return Backbone.View.extend({

    initialize: function () {          
        this.render();      
    },

    initMap: function () {

         myLatlng = new google.maps.LatLng(51.903679, -8.468274);

         mapOptions = {
            center: myLatlng,
            zoom: 12,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };

            map = new google.maps.Map(this.$el.find('#map-canvas')[0],
                                      mapOptions);


         marker = new google.maps.Marker({
            position: myLatlng,
            map: map,
            title: 'Christians Brothers College Cork'
        });

    },

    render: function () {
        this.$el.html(template({side_nav:side_nav}));
        this.initMap();       
    },


});

});

Here is a link to the app. When you click on "location", the map renders perfectly. But when you navigate anywhere else, then back to location, only a tiny portion of the map can be seen in the top left hand corner.

I tried doing, which was suggested here:

google.maps.event.trigger(map, 'resize').

but to no avail. Any ideas?


Solution

  • Your view works on a node not appended to the DOM, thus without size, a situation Google Map is not very fond of. It is your router, via PageSlider, that does append the node after your render function has occurred. Here is a demo of your predicament : http://jsfiddle.net/3C7g3/

    You have several options to solve it:

    • call google.maps.event.trigger(map, 'resize') after the node is inserted into the DOM (this bit of code corresponds to your router entry for the map)

      // assuming you stored the map object in your view
      require(["app/views/Map"], function (Map) {
          var view = new Map();
          slider.slidePage(view.$el);
          google.maps.event.trigger(view.map, 'resize');
       });
      

      http://jsfiddle.net/3C7g3/1/

    • insert the node into DOM before calling render. In your case, that probably means removing render from the view.initialize and calling view.render after container.append(page); in your slidePageFrom method.

      http://jsfiddle.net/3C7g3/2/

    • a more hackish way would be to temporarily add the element to the DOM, apply Google Maps, and then remove it from the DOM

      initMap: function () {
          // assuming a temp class that hides the element. For example,
         // .temp {position: absolute; visibility:hidden; }
          this.$el.addClass('temp');
          $('body').append(this.$el);
          // ...
          this.$el.remove();
          this.$el.removeClass('temp');
      }
      

      http://jsfiddle.net/3C7g3/3/