Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Candidat au Club
    Convertir une requête Ajax procédurale en objet
    Bonsoir j'ai un soucis pour passer mes requêtes ajax de procédural à orienté objet. Je dois, dans un premier temps, afficher une map ainsi que des markers, autant afficher la map en objet j'y arrive mais pour les markers je bloque. Je suis preneur de toute aide/information/solution/piste/variante...

    Voici le procédural qui fonctionne :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    let rouen = [49.436511, 1.090534]
    let myMap = L.map('map').setView(rouen, 13.5);
    L.tileLayer('https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', {
      maxZoom: 20,
      attribution: '&copy; Openstreetmap France | &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(myMap);
     
    $.ajax({
      url: "https://api.jcdecaux.com/vls/v3/stations?contract=rouen&apiKey=f31b2644b542ceea892be74f5fd48dc4337dc155",
      method: "GET",
      dataType: "json",
      success: addMarkers
    })
     
    function addMarkers(data) {
      for (let i = 0; i < data.length; i++) {
        let mark = L.marker([data[i].position.latitude, data[i].position.longitude]).addTo(myMap);
      }
    }

    Et la version orienté objet ou je coince pour afficher les markers :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    class Map {
      constructor() {
        this.lat = 49.436511;
        this.long = 1.090534;
        this.zoom = 13.5;
        this.myMap = L.map('map').setView([this.lat, this.long], this.zoom);
        this.maxZoom = 20;
        this.initializeMap();
        this.getAjax();
        this.addMarkers();
      };
     
      initializeMap() {
        L.tileLayer('https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', {
          maxZoom: this.maxZoom,
          attribution: '&copy; Openstreetmap France | &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
        }).addTo(this.myMap);
      }
     
      getAjax() {
        $.ajax({
          url: "https://api.jcdecaux.com/vls/v3/stations?contract=rouen&apiKey=f31b2644b542ceea892be74f5fd48dc4337dc155",
          method: "GET",
          dataType: "json",
          success: addMarkers
        })
      }
     
      addMarkers(data) {
        for (this.i = 0; this.i < this.data.length; this.i++) {
          L.marker(this.data[i].position.latitude, this.data[i].position.longitude[i]).addTo(this.myMap);
        }
      }
    };
     
    let mapRouen = new Map();

    Ainsi addMarkers du success n'est plus défini, je suppose que cela vient du fait que la requête ajax est englobé dans la méthode d'instance "getAjax" et est donc hors scope, mais je ne vois pas comment palier cela. J'ai aussi essayé de passer en objet la même requête sans utiliser jQuery mais en vain. En espérant ne pas avoir pondu un code trop long pour le forum, je vous remercie d'avance.

  2. #2
    Membre émérite
    Salut,

    Tout d'abord quand tu met ça :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    this.getAjax();this.addMarkers();
    , tu fais appel à la fonction addMarkers deux fois, une dans le success d'ajax de getAjax() et la deuxième après, ce qu'il ne faut pas faire !

    Quant à addMarkers, il faut ajouter le paramètre context:this dans ajax et gérer le résultat dans le callback done (au lieu de success, d'ailleurs tu dois toujours utiliser done et pas success) :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    getAjax() {
        $.ajax({
          url: "https://api.jcdecaux.com/vls/v3/stations?contract=rouen&apiKey=f31b2644b542ceea892be74f5fd48dc4337dc155",
          method: "GET",
          dataType: "json",
          context:this//attribuer ce paramètre à $.ajax afin d'utiliser le mot clef (this) dans le done, vu que getAjax() s'exécute dans le contexte du constructeur... donc l'objet de la classe Map. 
        })
        .done(function(marqueurs){
    	this.addMarkers(marqueurs);//sans le param context: this ça retourne une erreur !
         });
      }


    Et dans le constructeur, tu ne dois pas rappeler la fonction addMarkers :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    constructor() {
        this.lat = 49.436511;
        this.long = 1.090534;
        this.zoom = 13.5;
        this.myMap = L.map('map').setView([this.lat, this.long], this.zoom);
        this.maxZoom = 20;
        this.initializeMap();
        this.getAjax();
        /*this.addMarkers(); supprime là d'ici, pcq elle sera exécutée dans le done() d'ajax dès que les données seront disponible */
      };


    Après, je pense que tu dois écrire la fonction addMarkers avec la syntaxe de jQuery et utiliser $.each :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    addMarkers(data) {
        $(data).each(function(index,marker) {
    	  console.log("marker :",marker);//vérifie la console du navigateur si tu vois ça !
    	  L.marker([marker.position.latitude, marker.position.longitude])
               .addTo(this.myMap);
        });
      }

  3. #3
    Candidat au Club
    Bonjour,

    Avant tout merci pour ce retour. Cela ne fonctionne toujours pas mais j'ai tout de même avancé et compris certaines choses.

    Aucun markers ne s'affichent.
    Le console.log m'affiche dans la console seulement le premier marker de la liste/array puis s'ensuit l'erreur. TypeError : t is undefined.
    En savoir plus => RangeError: repeat count must be less than infinity and not overflow maximum string size.
    RangeError: le nombre de répétitions doit être inférieur à l'infini et ne pas dépasser la taille maximale de la chaîne.

    Cela me semble être une erreur de boucle, étant nouveau sur jQuery je ne me suis pas encore trop exercé sur les boucles, leur syntaxe etc..ce que je vais faire today.
    En regardant dans réseau, la requête a bien abouti (code 200) puis dans réponse je trouve bien les 25 objets de l'array.

    Je vais continuer mes recherches et vous tenir au courant.
    Merci encore.

  4. #4
    Membre émérite
    Salut,

    Je pense que le problème est dans this.myMap :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
     
    L.marker([marker.position.latitude, marker.position.longitude]).addTo(this.myMap);


    Si tu rajoute un deuxième paramètre "map" à la fonction addMarkers :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    addMarkers(data,map) {
        $(data).each(function(index,marker) {
    	  console.log("marker :",marker);
    	  L.marker([marker.position.latitude, marker.position.longitude]).addTo(map);
        });
      }


    Et au quand tu l'appelle, tu passe "this.myMap" dans les paramètres :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    .done(function(marqueurs){
    	this.addMarkers(marqueurs,this.myMap);
    });


    Cela devrait fonctionner.

  5. #5
    Modérateur

    Bonjour,
    le problème est effectivement dans l'utilisation du this, le contexte.

    Dans la fonction getAjax le problème se règle en fixant le contexte exécution comme mentionné par Toufik83.

    Par contre dans une boucle jQuery.each, le this représente l'objet en cours de traitement, donc le this.myMap plante, il faut donc sauvegarder ce contexte avant utilisation dans la boucle.
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
      addMarkers(datas) {
        // sauve le contexte pour utilisation dans la boucle
        const thisObj = this;
        $(datas)
          .each(function (index, data) {
            L.marker([data.position.latitude, data.position.longitude])
              .addTo(thisObj.myMap);
          });
      }

    ou ne pas passer par jQuery
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     addMarkers(datas) {
        datas.forEach((data) => {
          L.marker([d.position.latitude, d.position.longitude])
              .addTo(this.myMap);
        });
      }


    Pour complément, si tu utilises jQuery juste pour l'appel Ajax alors c'est franchement contre productif, tu pourrais tout autant passer par l'API Fetch, cela pourrait donner :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      recupDatas() {
        const url = "https://api.jcdecaux.com/vls/v3/stations?contract=rouen&apiKey=TON_API_KEY";
        // sauve le contexte pour utilisation dans le then()
        const thisObj = this;
        fetch(url)
          .then(function (response) {
            return response.json()
              .then(function (datas) {
                thisObj.addMarkers(datas);
              })
          });
      }

    ... de même pour l'affectation de la position, l'api a changé les références en retour lat -> latitude et lng -> longitude on se demande bien pourquoi d'ailleurs, tu peux utiliser la méthode Object.values, cela devient dans ce cas :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     addMarkers(datas) {
        datas.forEach((data) => {
          L.marker(Object.values(data.position))
              .addTo(this.myMap);
        });
      }

  6. #6
    Candidat au Club
    Bonjour,

    Merci a vous deux, cela fonctionne.