I've been through as many StackOverflow/google groups as I can imagine trying to figure this guy out.
I'm using BackboneJS to render a map that has a start location and an end location. On a fresh page/page refresh, I don't get this error, and the map and stuff work fine, for I am using jQuery's $(window).load(.....) function; however, when I dynamically render my View, I get this error-I believe-because the DOM hasn't loaded the DIV yet (failing with document.getElementById). I have tried all manner of different methods other than the $(window).load(), but I can't get anything which works for both use cases (fresh page load -- BackboneJS view loading). Trying to call the function right after the template doesn't work, either.
Any help would be appreciated.
Robert
View:
App.Views.MapShow = Backbone.View.extend({
initialize: function() {
_.bindAll(this, 'render');
var self = this;
$(window).load(function() {
self.renderMap();
});
},
render: function() {
this.renderTemplate();
},
renderTemplate: function() {
this.$el.html(JST['path/to/show/file']());
},
renderMap: function() {
var from = this.model.get('location_from');
var to = this.model.get('location_to');
var geocoder = new google.maps.Geocoder();
var map = new google.maps.Map(document.getElementById('mapCanvas'), {
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var directionsService = new google.maps.DirectionsService();
var directionsDisplay = new google.maps.DirectionsRenderer();
directionsDisplay.setMap(map);
var request = {
origin: from,
destination: to,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
});
HTML:
<div class="map" id="mapCanvas"></div>
I'd guess that your problem is that #mapCanvas
isn't in the DOM until after you try to access it so this:
document.getElementById('mapCanvas')
will give you a useless null
. You need to wait until #mapCanvas
is in the DOM before using it; you can't do something like this either:
map_canvas = this.$el.find('#mapCanvas')[0];
That will give you a valid ID but you'll confuse the Google Maps functions because it won't have a size so the map will be rendered oddly. This puts you back to waiting for everything to be in the DOM before binding your Google Maps stuff.
One way around this is to use setTimeout
with a delay of zero:
var _this = this;
setTimeout(function() { _this.renderMap() }, 0);
This looks strange bit it does work, this trick basically dumps your renderMap
call into the browser's work queue and it'll get around to running it once you've returned control to the browser.
You can also use _.defer
:
defer
_.defer(function, [*arguments])
Defers invoking the function until the current call stack has cleared, similar to using setTimeout with a delay of 0. Useful for performing expensive computations or HTML rendering in chunks without blocking the UI thread from updating.
This might be a better choice as it makes your intent explicit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With