2010-12-07 47 views
7

J'ai un module que j'ai créé pour Google Maps v3 que j'essaye de convertir en constructeur de vue de Backbone.js.Backbone.js avec Google Maps - problèmes avec ceci et les auditeurs

Voici mon module de vue à ce jour: Je vais vous expliquer les problèmes que je vais avoir après le 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); 
    } 

}); 

Le problème que je vais avoir est avec les écouteurs d'événements Google Maps et comment « cette » est gérée.

Au départ, je n'ai pas les méthodes et plutôt ces deux dans le bloc initialize dragMarker et dragMap:

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); 
}); 

Le problème que je rencontrais avec cette première approche est que « cette » à l'intérieur de ces fonctions anonymes visées "this.marker" et "this.map" respectivement. Le problème avec cette première approche était que dans le premier écouteur, je n'avais aucun moyen de faire référence à "this.map" et donc je ne pouvais pas faire de panTo(). Avec le second écouteur, je n'avais aucun moyen de faire référence à "this.marker" et je ne pouvais donc pas recentrer la carte autour de ce marqueur en utilisant setPosition(). J'ai alors pensé que je pourrais retirer les fonctions anonymes dans les écouteurs et les déclarer comme des méthodes de la vue, que j'effectuerais alors un _.bindAll (ceci, "dragMarker", "dragMap");

Le problème avec cette approche est que je devais alors d'écrire les auditeurs dans le bloc événement comme ceci:

google.maps.event.addListener(this.marker, "dragend", this.dragMarker()); 

google.maps.event.addListener(this.map, "dragend", this.dragMap()); 

Cela signifie que quand j'ai appelé le constructeur avec newmap = new pg.views.CreateMap; que "this.dragMarker()" et "this.dragMap()" ont été évalués immédiatement au lieu d'être évalués en tant que rappel lorsque l'événement "dragend" est déclenché.

Pas de problème, je pensais puis enveloppé dans les fonctions anonymes comme ceci:

google.maps.event.addListener(this.marker, "dragend", function() { 
    this.dragMarker(); 
}); 

google.maps.event.addListener(this.map, "dragend", function() { 
    this.dragMap(); 
}); 

Malheureusement, cela me ramène aussi à un problème plus tôt que « ce » ne « this.dragMarker » fait plus référence à l'objet parent, j'ai construit, mais à la place de se référer à "this.marker" à nouveau. Le même problème se produit avec le deuxième écouteur.

Je suis complètement coincé ici. Quelqu'un at-il des idées sur la façon dont je résous cela?

+0

La méthode correcte pour attacher un gestionnaire d'événements est la suivante: 'google.maps.event.addListener (this.marker," dragend ", this.dragMarker);' (sans les parenthèses). Mais cela ne résoudra pas votre problème de contexte. –

Répondre

6

Prendre les fonctions anonymes appelées dragend et lier explicitement.

_.bindAll(this, 'dragMarker', 'dragMap'); 
google.maps.event.addListener(this.marker, "dragend", this.dragMarker); 
/* etc ... */ 

De cette façon this sera toujours lié à createMap même si elle est appelée hors contexte.

+0

dans dragMarker: function() {}, comment puis-je l'obtenir de google.maps.event – nXqd

5

J'ai résolu ce problème en utilisant le common/self hack commun en 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); 
}); 

Si quelqu'un a une solution qui ne nécessite pas ce hack, je suis toutes les oreilles.

+0

Ce n'est pas vraiment un hack - c'est ce que j'aurais fait. –

+0

ce n'est pas un hack. Dougl Crockford parle de var that = this; dans ses vidéos YUI. – jspooner

+0

Aujourd'hui, j'utilise l'approche _.bind(). Je trouve que c'est beaucoup plus propre et il y a moins de chance de bousiller (comme oublier de mettre var devant soi = ceci, par exemple) –