I have a module I created for Google Maps v3 that I'm trying to convert into a Backbone.js view constructor.
Here's my view module so far: I'll explain the problems I'm having after the code:
pg.views.CreateMap = Backbone.View.extend({
tagName: "div",
className: "map",
events: {},
latitude: "-23.56432",
longitude: "-46.65183",
initialize: function() {
_.bindAll(this, 'render', 'dragMarker', 'dragMap');
this.latlng = new google.maps.LatLng(this.latitude, this.longitude);
var myOptions = {
zoom: 16,
center: this.latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new google.maps.Map($(this.el)[0], myOptions);
this.marker = new google.maps.Marker({
map: this.map,
position: this.latlng,
draggable: true
});
google.maps.event.addListener(this.marker, "dragend", this.dragMarker());
google.maps.event.addListener(this.map, "dragend", this.dragMap());
},
render: function() {
return this;
},
dragMarker: function() {
this.latlng = this.marker.getPosition();
this.map.panTo(this.latlng);
},
dragMap: function() {
this.latlng = this.map.getCenter();
this.marker.setPosition(this.latlng);
}
});
The problem I'm having is with the Google Maps event listeners and how "this" is handled.
I originally didn't have the dragMarker and dragMap methods and instead these two in the initialize block:
google.maps.event.addListener(this.marker, "dragend", function() {
this.latlng = this.marker.getPosition();
this.map.panTo(this.latlng);
});
google.maps.event.addListener(this.map, "dragend", function() {
this.latlng = this.map.getCenter();
this.marker.setPosition(this.latlng);
});
The problem I encountered with this first approach is that "this" inside those anonymous functions referred to "this.marker" and "this.map" respectively. The problem with this first approach was that in the first listener, I had no way of referring to "this.map" and therefore could not perform a panTo(). With the second listener, I had no way of referring to "this.marker" and therefore could not recenter the the map around that marker using setPosition().
I then thought that I could pull out the anonymous functions in the listeners and declare them as methods of the view, which I would then perform a _.bindAll(this, "dragMarker", "dragMap");
The problem with this approach is that I then had to write the listeners in the event block like so:
google.maps.event.addListener(this.marker, "dragend", this.dragMarker());
google.maps.event.addListener(this.map, "dragend", this.dragMap());
This meant that when I called the constructor with newmap = new pg.views.CreateMap; that the "this.dragMarker()" and "this.dragMap()" were evaluated immediately instead of being evaluated as a callback when the "dragend" event is triggered.
No problem I thought and then wrapped those up in anonymous functions like so:
google.maps.event.addListener(this.marker, "dragend", function() {
this.dragMarker();
});
google.maps.event.addListener(this.map, "dragend", function() {
this.dragMap();
});
Unfortunately this also brings me back to an earlier problem that the "this" in "this.dragMarker" no longer refers to the parent object I constructed, but instead refer to "this.marker" again. The same problem occurs with the second listener.
I'm completely stuck here. Anyone have any ideas on how I solve this?
Take the anonymous functions called on dragend
and bind explicitly.
_.bindAll(this, 'dragMarker', 'dragMap');
google.maps.event.addListener(this.marker, "dragend", this.dragMarker);
/* etc ... */
This way this
will always be tied to CreateMap even if called out of context.
I solved this problem by using the that/self hack common in Javascript.
var self = this;
google.maps.event.addListener(this.marker, "dragend", function() {
self.latlng = this.getPosition();
self.map.panTo(self.latlng);
});
google.maps.event.addListener(this.map, "dragend", function() {
self.latlng = this.getCenter();
self.marker.setPosition(self.latlng);
});
If anyone has a solution that doesn't require this hack, I'm all ears.
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