2014-09-04 3 views
1

J'ai un problème lors de l'utilisation de la fonction jquery.each() dans un jquery.getJSON. Dans mon code, il y a 2 types d'éléments dont je parle. "Sources" et "Streams" Je veux utiliser getJSON pour obtenir les sources, les parcourir et générer un en-tête d'accordéon. Puis, pour chacune de ces "sources", j'utilise à nouveau getJSON avec l'identifiant de cette source pour obtenir ses "flux" correspondants. Ensuite, j'ajoute ces flux à son corps d'accordéon sources, pour obtenir une liste de tous les flux, triés par leurs sources.

Mais il semble que pendant que j'obtiens le JSON, les instructions suivantes dans ma procédure sont déjà exécutées. Comme je construis de manière dynamique une grande chaîne HTML et l'ajoute à un élément en utilisant jQuery, la chaîne n'obtient pas toutes les données dont elle a besoin.

Le code se présente comme suit:

var html1 = "<div class='panel-group' id='manageAccordion'>"; 
$.getJSON(url, function(data){ 
    $.each(data, function(i, json){ 
     html1 += getAccordionPart(...); //creates the accordion for the given source 
    }); 

}).done(function(){ 
    html1 += "</div>"; 
    $('#elementList').html(html); 
}); 

function getAccordionPart(id, parent, count, json){ 
    //new string html2 is created and a bunch of stuff added 
    //... 
    html2 += "...."; 
    html2 += getAccordionBody(json); 
    html2 += "</div></div></div></div>"; 
    return html2 
} 

function getAccordionBody(json){ 
//new string "html3" gets created 
//... 

var url = standardUrl + "sources/" + encodeURIComponent(json.elementId) + "/streams"; 
$.getJSON(url, function(data) { 
    $.each(data, function(i, json) { 
     html3 += "<li class='list-group-item'>"; 
     html3 += json.name; 
     html3 += "</li>"; 
    }); 

}).done(function(){ 
    html3 += "</ul>"; 
    return html3; 
}); 

}

Ce que je finis spécifiquement avec est un en-tête d'accordéon qui a « non défini » dans ce son corps, parce qu'il semble la fonction getAccordionBody() n » t retourne avant que la chaîne html ne soit ajoutée au DOM.

Je l'ai déjà essayé de changer le $.getJSON-$.ajax avec async = false, sur mes deux $.getJSON appels, cela semble résoudre le problème que les déclarations n'exécutent pas dans l'ordre que je veux qu'ils, mais il est horriblement lent et renvoie undefined de toute façon pour une raison quelconque ..

Des suggestions? Ai-je raté quelque chose de vraiment stupide?

+0

Il sera bon de générer le code HTML sur le serveur. Comme il dose ne nécessite aucune entrée de l'utilisateur du client avec la fin dans la boucle. Il sera donc préférable de créer cette chaîne html sur le serveur. Ce sera beaucoup plus rapide. Dans tous les cas, si votre design est obligatoire, essayez $ .ajax avec l'option cache: false et async: false. – Priyank

+1

Il est fou d'essayer et de faire ce genre de choses dans jQuery quand il y a des bibliothèques mvvm appropriées comme knock-out et angulaire – andrew

Répondre

1

il semble que la fonction getAccordionBody() ne retourne pas avant la chaîne html est ajouté au DOM

C'est exact. Votre façon de returning the response (html3) from ajax est défectueuse - vous ne pouvez pas return d'un gestionnaire done.

Vous pouvez toutefois résoudre ce problème en utilisant des promesses. Chaque fonction retourne une promesse afin qu'ils soient facilement enchaînées et then est utilisé pour transformer les données et obtenir une nouvelle promesse pour elle:

$.getJSON(url).then(function(data){ 
    return $.when.apply($, $.map(data, function(i, json){ 
     return getAccordionPart(…); //creates the accordion for the given source 
    }).then(function() { 
     var html1 = "<div class='panel-group' id='manageAccordion'>"; 
     html1 += Array.prototype.join.call(arguments, "\n"); 
     html1 += "</div>"; 
     return html1; 
    }); 
}).done(function(html){ 
    $('#elementList').html(html); 
}); 

function getAccordionPart(id, parent, count, json){ 
    return getAccordionBody(json).then(function(result) { 
     var html2 = "…"; //new string html2 is created and a bunch of stuff added 
     html2 += result; 
     html2 += "</div></div></div></div>"; 
     return html2; 
    }); 
} 

function getAccordionBody(json) { 
    var url = standardUrl + "sources/" + encodeURIComponent(json.elementId) + "/streams"; 
    return $.getJSON(url).then(function(data) { 
     var html3 = "…"; //new string "html3" gets created 
     $.each(data, function(i, json) { 
      html3 += "<li class='list-group-item'>"; 
      html3 += json.name; 
      html3 += "</li>"; 
     }); 
     html3 += "</ul>"; 
     return html3; 
    }); 
} 
+0

Merci, je l'ai eu à travailler, même si je n'ai pas encore pleinement compris – Cuddl3s

+0

Vous voulez vous familiariser avec les promesses (https://github.com/kriskowal/q/wiki/General-Promise-Resources) bien sûr :-) – Bergi

0

Plutôt que d'utiliser la synchronisation appelle, vous pouvez utiliser le modèle différé/promesse - http://api.jquery.com/deferred.promise/.

  • Vous aurez besoin de retourner la promesse de générer une fonction d'accordéon.
  • Vous devrez mettre en file d'attente vos appels de fonction de génération d'accordéons.
  • Ensuite, effectuez l'opération d'ajout séquentiellement au fur et à mesure que les promesses sont résolues.
0

Vous devez collecter d'abord tout ce qui est nécessaire pour « getAccordionPart » et " getAccordionBody "(par exemple: encodeURIComponent (json.elementId)) dans un tableau global.comme:

var arrIds = []; 

$.getJSON(url, function(data){ 
$.each(data, function(i, json){ 
    arrIds.push(encodeURIComponent(json.elementId))//collect everything which is required for "getAccordionPart" and "getAccordionBody" 
}); 

itérer puis sur cette collection et de rassembler toutes les données pour le corps de ces accordian ids dans une variable globale.

var bodyData = {}; 
$.each(arrIds, function(){ 
var url = standardUrl + "sources/" + this + "/streams"; 
$.getJSON(url, function(data) { 
    bodyData[this] = data;//collect all the Data for accordian body of these ids 
}}); 

font également un changement Litle dans getAccordionPart comme:

function getAccordionPart(id, parent, count, /*json*/ elementId){ 
//new string html2 is created and a bunch of stuff added 
//... 
html2 += "...."; 
html2 += getAccordionBody(elementId); 
html2 += "</div></div></div></div>"; 
return html2 
} 

changer aussi getAccordionBody comme:

function getAccordionBody(/*json*/ elementId){ 
//new string "html3" gets created 
//... 

var data = bodyData[elementId]; 
    $.each(data, function(i, json) { 
     html3 += "<li class='list-group-item'>"; 
     html3 += json.name; 
     html3 += "</li>"; 
    }); 
html3 += "</ul>"; 
    return html3; 
} 

Votre appel sera également modifié:

$.each(arrIds , function(){ 
    html1 += getAccordionPart(,,,this); //creates the accordion for the given source 
}); 

Vous Code final l être:

var arrIds = []; 

$.getJSON(url, function(data){ 
$.each(data, function(i, json){ 
    arrIds.push(encodeURIComponent(json.elementId))//collect everything which is required for "getAccordionPart" and "getAccordionBody" 
}); 

var bodyData = {}; 
$.each(arrIds, function(){ 
var url = standardUrl + "sources/" + this + "/streams"; 
$.getJSON(url, function(data) { 
    bodyData[this] = data;//collect all the Data for accordian body of these ids 
}}); 

function getAccordionPart(id, parent, count, /*json*/ elementId){ 
    //new string html2 is created and a bunch of stuff added 
    //... 
    html2 += "...."; 
    html2 += getAccordionBody(elementId); 
    html2 += "</div></div></div></div>"; 
    return html2 
    } 

function getAccordionBody(/*json*/ elementId){ 
//new string "html3" gets created 
//... 

var data = bodyData[elementId]; 
    $.each(data, function(i, json) { 
     html3 += "<li class='list-group-item'>"; 
     html3 += json.name; 
     html3 += "</li>"; 
    }); 
html3 += "</ul>"; 
    return html3; 
} 

$.each(arrIds , function(){ 
    html1 += getAccordionPart(,,,this); //creates the accordion for the given source 
}); 
Questions connexes