Faire que les fonctions attendent que l’appel AJAX soit terminé avec jQuery

J’essaie de développer une classe en JavaScript que je peux utiliser pour accéder facilement à un chargement de données rassemblées par une requête AJAX. Le seul problème est que je dois rendre les membres de la classe accessibles uniquement une fois l’appel AJAX terminé. Idéalement, ce que je voudrais en arriver est quelque chose où je peux appeler cela dans un script:

courses.getCourse('xyz').complete = function () { // do something with the code } 

Et cela ne se déclenche que lorsque l’appel AJAX est terminé et que les structures de données de la “classe” sont prêtes à être utilisées. Idéalement, je ne veux pas avoir à créer un membre .complete pour chaque fonction de la classe.

Voici la “classe” que j’essaie de faire jusqu’ici:

 var model_courses = (function() { var cls = function () { var _storage = {}; // Used for storing course related info _storage.courses = {}; // Used for accessing courses directly _storage.references = new Array(); // Stores all available course IDs var _ready = 0; $.ajax({ type: "GET", url: "data/courses.xml", dataType: "xml", success: function(xml) { $(xml).find("course").each(function() { _storage.courses[$(this).attr('id')] = { title : $(this).find('title').text(), description : $(this).find('description').text(), points : $(this).find('points').text() } _storage.references.push($(this).attr('id')) }) } }) console.log(_storage.courses) } cls.prototype = { getCourse: function (courseID) { console.log(cls._storage) }, getCourses: function () { return _storage.courses }, getReferences: function (), return _storage.references } } return cls })() 

Pour le moment, getCourse sera déclenché avant la fin de la demande AJAX et, de toute évidence, il n’aura aucune donnée à accéder.

Toutes les idées seront grandement appréciées, je suis coincé sur celui-ci!

Les modifications suivantes vous permettent d’effectuer la demande AJAX une seule fois et vous pouvez appeler votre fonction comme suit:

 courses.getCourse('xyz', function(course){ // Use course here }); 

Voici les changements

 var model_courses = (function() { // This is what gets returned by the $.ajax call var xhr; var _storage = {}; // Used for storing course related info _storage.courses = {}; // Used for accessing courses directly _storage.references = []; // Stores all available course IDs var cls = function () { xhr = $.ajax({ type: "GET", url: "data/courses.xml", dataType: "xml", success: function(xml) { $(xml).find("course").each(function() { _storage.courses[$(this).attr('id')] = { title : $(this).find('title').text(), description : $(this).find('description').text(), points : $(this).find('points').text() } _storage.references.push($(this).attr('id')) }); } }); } cls.prototype = { // Made changes here, you'd have to make the same // changes to getCourses and getReferences getCourse: function (courseID, callback) { if (xhr.readyState == 4) { callback(_storage.courses[courseID]); } else { xhr.done(function(){ callback(_storage.courses[courseID]); }) } }, getCourses: function () { return _storage.courses }, getReferences: function (), return _storage.references } } return cls })() 

En model_courses , votre modèle de module ne fonctionnera pas très bien si vous devez instancier deux de ces objects model_courses , car les objects de stockage sont tous partagés dans la fermeture de votre fonction d’appel automatique. En général, vous ne mélangez pas le modèle de module avec des prototypes (renvoi d’un constructeur à partir d’un module), sauf si vous savez vraiment ce que vous faites, c’est-à-dire que les variables de fermeture partagées fonctionnent comme des propriétés statiques de votre classe .

C’est ce que je ferais si j’étais vous (puisque vous voulez vraiment des variables privées)

 function ModelCourses() { var storage = { courses: {}, references: [] }; var xhr = $.ajax({ type: "GET", url: "data/courses.xml", dataType: "xml", success: function(xml) { $(xml).find("course").each(function() { storage.courses[$(this).attr('id')] = { title : $(this).find('title').text(), description : $(this).find('description').text(), points : $(this).find('points').text() } storage.references.push($(this).attr('id')) }) } }); this.getCourse = function(courseId, callback) { function getCourse() { callback(storage.courses[courseID]) } if (xhr.readyState == 4) { getCourse(); } else { xhr.done(getCourse); } }; } 

jQuery gère déjà cela pour vous en utilisant des objects différés, à moins que je ne comprenne pas ce que vous cherchez.

 var courses = { getCourse: function (id) { return $.ajax({url:"getCourse.php",data:{id:id}); } }; courses.getCourse("history").done(function(data){ console.log(data); }); 

Je sais que ce n’est pas exactement ce que vous recherchez, j’espère que c’est suffisant pour vous pousser dans la bonne direction. Les objects différés sont géniaux.

Dans getStorage soit append une vérification pour savoir s’il ya des données à voler (préféré), soit rendre la méthode “réelle” privée plutôt que de la publier quand elle contient des éléments auxquels elle peut accéder. (Je recommanderais le premier, sinon vous obtiendrez des exceptions pour appeler une méthode qui n’existe pas sur un object).

Vous pouvez définir une fonction getData qui exécuterait la demande ajax et prendrait le getCourse comme un rappel. getData pourrait éventuellement stocker localement le résultat de l’appel Ajax et tester le stockage local avant d’effectuer l’appel ajax.

Vous pouvez également spécifier un membre privé pour permettre à l’appel ajax d’être exécuté une seule fois. Vous voudrez peut-être vérifier underscore.js pour un outil pratique

Voici un exemple de code court:

 cls.prototype.getData = function(callback) { /*perform ajax call or resortingeve data from cache*/ callback() } cls.prototype.getCourse = function(id) { this.getData(function() { /*do something with the data and the id you passed*/ } }