最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - Backbone.js with Google Maps - problems with this and listeners - Stack Overflow

matteradmin3PV0评论

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 pletely stuck here. Anyone have any ideas on how I solve this?

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 pletely stuck here. Anyone have any ideas on how I solve this?

Share Improve this question asked Dec 7, 2010 at 16:54 Andrew De AndradeAndrew De Andrade 3,6165 gold badges34 silver badges37 bronze badges 1
  • The correct way to attach event handler is like this - google.maps.event.addListener(this.marker, "dragend", this.dragMarker); (without the parentheses). But this won't solve your context problem. – Chetan S Commented Dec 7, 2010 at 18:31
Add a ment  | 

2 Answers 2

Reset to default 6

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 mon 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.

Post a comment

comment list (0)

  1. No comments so far