Erreurs de style dans mon fichier JS utilisant GMaps ?

HTML5, CSS3, Javascript, support des mobiles... Que penser de votre site ? Vous manquez d'informations pour la construction d'un site qui puisse s'afficher correctement partout ? C'est un problème simple, un peu complexe ? Venez ici !
Répondre
Thomas
Varan
Messages : 1907
Inscription : 07 janv. 2004, 17:29

Erreurs de style dans mon fichier JS utilisant GMaps ?

Message par Thomas »

Bonsoir,

J'ai "écrit" un script permettant de géolocaliser une adresse grâce à l'API de Google Maps. Pour cela j'ai fait une page avec deux formulaires, un pour rentrer l'adresse et vérifier via une carte que c'est la bonne et l'autre pour valider les coordonnées récupérer par le premier formulaire.

J'aimerais d'abord savoir si le script à l'air "mauvais" ou pas. Je ne m'y connais pas en JavaScript encore.
D'autre part j'ai un problème. Dans geocode.js j'ai commenté deux lignes servant normalement à mettre à jour les coordonnées lorsqu'on déplace le marqueur sur la carte mais ça ne fonctionne pas (surement à cause de portée de variables). Comment contourner le problème ? Merci d'avance.

PS : ce code fonctionne uniquement en utilisant http://localhost/ (histoire de key pour l'API).

index.html :

Code : Tout sélectionner

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
    <title>Google Maps API : Geocoding</title>

    <script src="http://www.google.com/jsapi?key=ABQIAAAAnfs7bKE82qgb3Zc2YyS-oBT2yXp_ZAY8_ufC3CFXhHIE1NvwkxSySz_REpPq-4WZA27OwgbtyR3VcA" type="text/javascript"></script>
    <script src="./geocode.js" type="text/javascript"></script>
	<script type="text/javascript">
	google.load("maps", "2", {"language" : "fr"});
	google.setOnLoadCallback(initialize);
	</script>
  </head>
  <body>
      <p>Rentrez votre adresse entière. Exemple : <em>10 route de boncourt, 28260 Anet, france</em> ou <em>rabat, morrocco</em>.</p>
      <noscript><p>Vous devez activer JavaScript.</p></noscript>
      <form action="#" onsubmit="showLocation(); return false;">
      <fieldset>  
        <p><label for="q">Trouver les coordonnées de votre ville&nbsp;:</label><br/>
        <input type="text" name="q" id="q" value="" /> <input type="submit" name="find" value="(1) Rechercher" /></p>
        <div id="map" style="width: 400px; height: 300px"></div> 
      </fieldset>
      </form>
      
      <form method="post" action="#">
      <fieldset>
        <p><input id="champlat" name="latitude" type="hidden" value="" />
        <input id="champlong" name="longitude" type="hidden" value="" />
        <input id="champq" name="q" type="hidden" value="" /></p>
        <input name="update_location" value="(2) Enregistrer l'adresse" type="submit"/>
      </fieldset>
      </form>
</body>
</html>

geocode.js :

Code : Tout sélectionner

var map;
var geocoder;

function initialize()
{
  // Creation de la carte via Google Maps API v2
  map = new google.maps.Map2(document.getElementById("map"));
  
  // Centrage de la carte sur le monde
  map.setCenter(new google.maps.LatLng(34, 0), 1);
  
  // Permeter d'ajouter les mini-controles pour zommer/dezoomer
  map.addControl(new google.maps.SmallMapControl());
  
  // Initialise le client geocode    
  geocoder = new google.maps.ClientGeocoder();
}

// Fonction appellée si le geocoder renvoie une réponse !
// Il affiche un marqueur à l'endroit indique par l'adresse
// ainsi qu'une bulle info "Centre ville de l'adresse tapée"
function addAddressToMap(response)
{
  // Efface le marqueur si il y en a un
  map.clearOverlays();

  if (!response || response.Status.code != 200)
  {
    alert("Desole, nous n'avons pas reussi a trouver les coordonnees correspondant cette adresse :"+place.address+". Verifier que vous avez bien ecrit le nom de la ville et du pays, sinon essayez avec le nom d'une ville plus grande.");
  }
  else
  {
    place = response.Placemark[0];
    point = new google.maps.LatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
    marker = new google.maps.Marker(point, {draggable : true});

	google.maps.Event.addListener(marker, "dragend", function() {
		// On essaye de remplir les champs du deuxième formulaire
	    //document.getElementById('champlat').value=place.Point.coordinates[1];
	    //document.getElementById('champlong').value=place.Point.coordinates[0];
  	});	

    map.addOverlay(marker);	
    map.setCenter(new google.maps.LatLng(place.Point.coordinates[1], place.Point.coordinates[0]), 9);

	// On remplit les champs du deuxième formulaire
    document.getElementById('champlat').value=place.Point.coordinates[1];
    document.getElementById('champlong').value=place.Point.coordinates[0];
    document.getElementById('champq').value=place.address;  
  }
}

function showLocation()
{
  var address = document.forms[0].q.value;
  
  // On géocode l'adresse
  geocoder.getLocations(address, addAddressToMap);
}
Message envoyé avec : Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; fr; rv:1.9.0.1) Gecko/2008070206 Firefox/3.0.1
Anciennement Toto.
Benoit
Administrateur
Messages : 4894
Inscription : 19 juil. 2003, 10:59

Message par Benoit »

Tu as en effet un problème de visibilité car tu n'es plus dans la fonction addAdressToMap où ta variable « place » est déclarée mais dans une fonction anonyme associée à un évènement où ce « place » ne signifie plus rien.

Pour que ça fonctionne, il faudrait par exemple que tu mettes « place » en variable globale (en la déclarant juste après map et geocoder).
♫ Li tens s'en veit, je n'ai riens fais ;
Li tens revient, je ne fais riens. ♪
martin
Varan
Messages : 1074
Inscription : 21 janv. 2004, 16:23

Message par martin »

Ce coup ci, je ne suis pas d'accord avec Benoit ;) :
la variable place est définie dans le même "scope" que la déclaration de la fonction, c'est donc une closure, son contenu est donc accessible dans le corps de la fonction.

D'ailleurs ton exemple fonctionne chez moi, quand je décommente les 2 lignes ! Et sans passer par localhost, juste en file:///. Le DOM inspector montre que les 2 inputs sont correctement garnis de leur valeurs.
Benoit
Administrateur
Messages : 4894
Inscription : 19 juil. 2003, 10:59

Message par Benoit »

Il me semblait que pour faire une closure il aurait fallu utiliser un objet (éventuellement la fonction elle-même) et lui assigner la variable comme membre « this ». Il me semblait avoir déjà eu un problème de visibilité avec ce genre de code, mais si ce n'est pas nécessaire tant mieux.

Par contre je remarque à présent que « place » n'est pas déclarée avec var, donc ce n'est pas une variable locale à la fonction, c'est un truc plus bizarre.
♫ Li tens s'en veit, je n'ai riens fais ;
Li tens revient, je ne fais riens. ♪
martin
Varan
Messages : 1074
Inscription : 21 janv. 2004, 16:23

Message par martin »

Benoit a écrit :Il me semblait que pour faire une closure il aurait fallu utiliser un objet (éventuellement la fonction elle-même) et lui assigner la variable comme membre « this ». Il me semblait avoir déjà eu un problème de visibilité avec ce genre de code, mais si ce n'est pas nécessaire tant mieux.
Les closures sont toujours délicates à manipuler, j'ai des soucis parfois aussi pour m'en servir ;) .
Benoit a écrit :Par contre je remarque à présent que « place » n'est pas déclarée avec var, donc ce n'est pas une variable locale à la fonction, c'est un truc plus bizarre.
Pour moi, le mot clé "var" devrait être utilisé ici, mais néanmoins elle doit être ici considérée comme locale.

Mais je me suis quand même trompé, effectivement le drag'n'drop ne fonctionne pas. En fait, il fonctionne, mais ne fait pas ce que voudrait Toto ;) .
Il ne veut pas récupérer les coordonnées de place, mais de marker.

Ce code semble fonctionner chez moi :

Code : Tout sélectionner

/ Fonction appellée si le geocoder renvoie une réponse !
// Il affiche un marqueur à l'endroit indique par l'adresse
// ainsi qu'une bulle info "Centre ville de l'adresse tapée"
function addAddressToMap(response)
{
  // Efface le marqueur si il y en a un
  map.clearOverlays();

  if (!response || response.Status.code != 200)
  {
    alert("Desole, nous n'avons pas reussi a trouver les coordonnees correspondant cette adresse :"+place.address+". Verifier que vous avez bien ecrit le nom de la ville et du pays, sinon essayez avec le nom d'une ville plus grande.");
  }
  else
  {
    var place = response.Placemark[0];
    var point = new google.maps.LatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
    var marker = new google.maps.Marker(point, {draggable : true});
    
    var champlat = document.getElementById('champlat');
    var champlong = document.getElementById('champlong');
    
    var myfunc = function() {
       champlat.value = this.getLatLng().lat();
       champlong.value = this.getLatLng().lng();
     };

   google.maps.Event.addListener(marker, "dragend", myfunc);

    map.addOverlay(marker);   
    map.setCenter(new google.maps.LatLng(place.Point.coordinates[1], place.Point.coordinates[0]), 9);

   // On remplit les champs du deuxième formulaire
    champlat.value=place.Point.coordinates[1];
    champlong.value=place.Point.coordinates[0];
    document.getElementById('champq').value=place.address; 
  }
}
Au passage, j'ai utilisé les closures champlat et champlong, et le this dans myfunc correspond à marker.
martin
Varan
Messages : 1074
Inscription : 21 janv. 2004, 16:23

Message par martin »

martin a écrit :
Benoit a écrit :Par contre je remarque à présent que « place » n'est pas déclarée avec var, donc ce n'est pas une variable locale à la fonction, c'est un truc plus bizarre.
Pour moi, le mot clé "var" devrait être utilisé ici, mais néanmoins elle doit être ici considérée comme locale.
"pour moi" n'ayant pas grande valeur ;) , et plus il faux ici, je me corrige moi même :D :
En vérifiant dans le DOM inspector, si on omet le mot clé var, la variable place est bien globale !
Thomas
Varan
Messages : 1907
Inscription : 07 janv. 2004, 17:29

Message par Thomas »

Ok merci je commence à mieux comprendre. Par exemple tu as rajouté "var" devant la ligne place = response.Placemark[0]; et quelques autres lignes. Il faut le faire à chaque déclaration de variable (c'est plus propre ?) ?

D'ailleurs on m'avais dit (mais pour un autre langage que JavaScript) qu'il ne faut toujours évité d'utiliser des variables globales. Sauf que là j'en ai au omins deux (map et geocoder).

Message envoyé avec : Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; fr; rv:1.9.0.1) Gecko/2008070206 Firefox/3.0.1
Anciennement Toto.
Benoit
Administrateur
Messages : 4894
Inscription : 19 juil. 2003, 10:59

Message par Benoit »

En fait ce ne sont jamais vraiment des variables globales au sens où on l'entendrait dans un autre langage, ce sont des variables locales associées à la page courante. Il n'y a pas vraiment de raison de ne pas en utiliser à part que ça "pollue" l'espace de nommage "global". Dans ce cas-ci, il est clair que la carte et le géocodeur sont "globaux" à la page. Je dirais que le marqueur l'est aussi, mais c'est vrai qu'on peut le voir comme une partie de la carte.

Martin : je me disais bien qu'il fallait utiliser this quelque part pour faire une closure, effectivement c'était sur le marker :)
♫ Li tens s'en veit, je n'ai riens fais ;
Li tens revient, je ne fais riens. ♪
martin
Varan
Messages : 1074
Inscription : 21 janv. 2004, 16:23

Message par martin »

Pour compléter Benoit sur les variables globales : quand tu déclares var map; (au début de ton script), l'objet de plus haut niveau, window, a une nouvelle propriété map.
Tu peux le vérifier par exemple dans le DOM inspector. Ouvres-le, sélectionne l'objet DOM de plus haut niveau (#document), et sélectionne le panneau 'Javascript Object'. Déplis 'sujet', trouve et déplie 'defaultView [object Window]', tu y trouveras la propriété 'map' ;) .
Martin : je me disais bien qu'il fallait utiliser this quelque part pour faire une closure, effectivement c'était sur le marker :)
Non ;) , les closures en question sont bien champlat et champlong. Si dans myfunc() on utilise pas le mot clé 'this', mais par exemple un simple alert(champlat);, çà fonctionne.
Le mot clé this représente l'object marker parce que je suppose (j'ai pas décortiqué l'API google, mais çà semble logique) que addListener se sert de addEventListener, et enregistre donc un événement avec notre fonction sur lui, tout simplement.

Ce qui est souvent pratique, c'est de créer une closure sur le this d'un objet courant, effectivement, pour y avoir accès dans un contexte différent.
genre :

Code : Tout sélectionner

// un contexte dans un objet
var self = this;
function myfunction() {
    alert(self);
// les propriétés et méthodes du this au dessus sont accessible via self
}
Une traduction partielle en français d'un bon article sur les closures, pout ceux que çà intéresse.
martin
Varan
Messages : 1074
Inscription : 21 janv. 2004, 16:23

Message par martin »

Toto a écrit :Ok merci je commence à mieux comprendre. Par exemple tu as rajouté "var" devant la ligne place = response.Placemark[0]; et quelques autres lignes. Il faut le faire à chaque déclaration de variable (c'est plus propre ?) ?
Le problème n'est pas que c'est plus propre, mais que la portée de la variable n'est pas la même !
var place = ... => la variable est locale
place = ... => visiblement Firefox ne trouve pas de variable locale déjà crée s'appelant map, il n'en trouve pas non plus de globale, et donc en crée une globale.

déclaration de variable, où que ce soit, == utilisation du mot clé 'var' ;) .

Du moins, c'est ce que je comprend, j'espère ne pas avoir écrit des aneries ;) .
Thomas
Varan
Messages : 1907
Inscription : 07 janv. 2004, 17:29

Message par Thomas »

Merci pour vos réponses. Sur un autre script j'ai un problèmes de portée, je vais d'abord essayer de le corriger avant de venir vous voir.

Message envoyé avec : Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; fr; rv:1.9.0.1) Gecko/2008070206 Firefox/3.0.1
Anciennement Toto.
Répondre

Qui est en ligne ?

Utilisateurs parcourant ce forum : Aucun utilisateur inscrit et 6 invités