2014-12-16 14 views
5

Sto utilizzando le seguenti funzioni Javascript per visualizzare una galleria di immagini.Javascript/JQuery - come chiamare una funzione al completamento della funzione precedente

function disp_pics(currObj,table){ 
    if(currObj != "none"){ 
     $("div .checkout2").removeClass("checkout2").addClass("checkout"); 
     $(currObj).closest("div").removeClass("checkout").addClass("checkout2"); 
    } 

    function getData(table){ 
     return $.ajax({ 
      url: "newphoto_gallery_display.php", 
      type: "GET", 
      data: { 
       table: table 
      }, 
      dataType: "html" 
     }); 
    } 

    function display_result(data){ 
     var dfd = new $.Deferred(); 
     dfd.done(equalise); 
     $("#ajaxoutput").html(data); 
     setTimeout(function() { 
      dfd.resolve(); 
     }, 1000); 
    } 

    function equalise(){ 
     var highestBox = 0; 
     $('.photodisplay').each(function(){ 
      if($(this).height() > highestBox) { 
       highestBox = $(this).height(); 
      } 
     }); 
     $('.photodisplay').height(highestBox); 
    } 

    var promise=getData(table); 
    promise.success(function (data) { 
     promise.done(display_result(data)); 
    }); 
}; 

La funzione getData recupera i dati delle immagini da un database. La funzione display_result invia quindi i dati al div id "ajaxoutput". Le immagini vengono visualizzate insieme ai dati rilevanti nelle caselle (tabelle HTML con un bordo). La funzione equalize viene quindi chiamata per rendere tutte le caselle di uguale altezza.

Senza il ritardo nel display_result viene richiamata la funzione di equalizzazione prima che tutte le immagini e i dati siano stati visualizzati e quindi confonda il display. C'è un modo per eliminare il ritardo e chiamare la funzione equalize solo quando display_result ha terminato l'output di tutti i dati sul div ajaxoutput?

Ho provato tutti i tipi di combinazioni Deferred e $ .quando ....... poi ...., ma non sono riuscito a ottenere il risultato desiderato senza ritardare lo script, che non è l'ideale . Qualsiasi suggerimento sarebbe benvenuto.

+0

Qual è il promise.done dovrebbe realizzare? È già fatto attraverso il successo. – Scottie

+0

È possibile utilizzare callback o promesse –

risposta

-1

Potete eseguirli in modo sincrono?

function display_result(data){ 
    $("#ajaxoutput").html(data); 
    equalise(); 
} 

Sono abbastanza sicuro che la funzione .html è una chiamata sincrona, in modo che il ridimensionamento avverrà dopo questo.

Modificato: che aspetto hanno i dati provenienti dalla chiamata ajax? È solo un mucchio di tag img? Se è così, probabilmente staresti meglio caricando l'immagine in ajax e codificandola nel codice HTML te stesso.

+0

L'intero punto della domanda è che l'OP non può eseguirli in modo sincrono. Questo non funziona. – jfriend00

+0

No, l'ho provato, ma l'equalizzazione viene chiamata prima che tutto l'HTML sia visualizzato in #ajaxoutput. I dati sono simili al seguente: – CodingCodger

+0

Siamo spiacenti: modifica scaduta. No, l'ho provato, ma l'equalizzazione viene chiamata prima che tutto l'HTML sia visualizzato in #ajaxoutput. I dati sono troppo lunghi perché io possa postare qui, ma consiste in una serie di tabelle, visualizzate in linea, ognuna delle quali contiene un'immagine e informazioni (come titolo, dimensioni, ecc.). Il numero di righe della tabella contenenti le informazioni. differisce da un tavolo all'altro, rendendo quindi le tabelle altezze diverse. Pertanto ho bisogno di rendere tutte le altezze del tavolo uguali dopo che vengono visualizzate per riordinare il display. – CodingCodger

5

Se il problema è che è necessario sapere quando sono state caricate tutte le immagini HTML applicate a #ajaxoutput (e quindi la loro dimensione è nota al browser), è possibile farlo in questo modo controllando l'onload evento per ciascuna delle immagini aggiunte al codice HTML:

function display_result(data){ 
    var dfd = new $.Deferred(); 
    var imgWaiting = 0; 
    $("#ajaxoutput").html(data).find("img").each(function() { 
     if (!this.complete) { 
      // img is still loading, install a load handler so we know when it's done 
      ++imgWaiting; 
      this.onload = this.onerror = function() { 
       --imgWaiting; 
       if (imgWaiting === 0) { 
        dfd.resolve(); 
       } 
      } 
     } 
    }); 
    if (imgWaiting === 0) { 
     dfd.resolve(); 
    } 
    return dfd.promise(); 
} 

Poi, si può fare:

return getData(table).then(display_result).then(equalise); 

che è un modello di design classico con promesse per la serializzazione diverse operazioni asincrone.

+0

Ho bisogno di controllare questo su un computer più lento, ma sul mio PC funziona! Grazie mille! Ho lottato con questo per giorni! – CodingCodger

+0

Se 'HTMLImageElement.complete 'è affidabile (sotto qualunque cosa! Doctype viene usato) allora questa risposta dovrebbe essere affidabile. Tuttavia, l'esperienza mi ha insegnato a non fidarmi di 'HTMLImageElement.complete'. –

+0

@ Roamer-1888 - Ho sempre trovato che 'img.complete 'è affidabile quando un'immagine viene caricata originariamente per la prima volta. Non ho sempre trovato '.complete' o l'evento' load' per essere affidabile quando si imposta una nuova proprietà '.src' sull'immagine (in particolare nelle vecchie versioni di IE se la memoria mi serve). Ma, l'esempio dell'OP è solo quando si carica l'immagine per la prima volta, quindi penso che '.complete' stia bene qui. – jfriend00

2

È necessario eliminare il ritardo di timeout poiché non è garantito che sia sufficientemente lungo per il caricamento delle immagini (server lento, Internet lento ecc.).

Purtroppo la soluzione "corretta" hai cercato non è il più semplice, principalmente a causa del fatto che si può accedere solo i nodi img di interesse dopo la dichiarazione $("#ajaxoutput").html(data) li mette in atto. Nella dichiarazione che segue quella, sarà incerto (a causa del comportamento del browser) se le immagini sono già state caricate (dalla cache) o meno. Il semplice inserimento di un gestore "onload" sarebbe quindi inaffidabile.

Una soluzione è creare un gruppo di off-schermo nodi img che rispecchiano quelli "#ajaxoutput" e di "promisify" loro in modo tale che le loro proprietà 'src' sono impostate dopo fissaggio "onload" (e "onerror") gestori.

Il codice non è semplice da seguire, quindi ho fatto del mio meglio per fornire commenti esplicativi.

function display_result(data) { 
    //First a function that creates a promisified <img> node, and returns its promise. 
    //<img> nodes created here are not appended to the DOM. 
    function imgPromise(index, imgNode) { 
     return $.Deferred(function(dfrd) { 
      //Note the order here - the onload/onerror handler is attached before the src attribute is set. 
      //Note also that both onload/onerror cause the deferred to be resolved, as you don't want any failures to prevent calling `equalise()`. 
      $("<img/>").on('load error', dfrd.resolve).attr('src', imgNode.src); 
     }).promise(); 
    } 

    //A lot happens in the next line ... 
    // * "#ajaxoutput" is given some HTML 
    // * any freshly created image nodes in "#ajaxoutput" are discovered 
    // * `imgPromise()` is called for each img node in turn and the returned promises are stuffed into an array 
    // * the array is assigned to local var `promises`. 
    var promises = $("#ajaxoutput").html(data).find("img").map(imgPromise); 

    //Finally, `$.when()` returns a promise that is resolved when all `promises` have settled. 
    //This "summary promise" is returned. 
    return $.when.apply(null, promises); 
} 

Senza i commenti, si vedrà che questo è in realtà molto conciso e, auspicabilmente, un po 'meno paura.

function display_result(data) { 
    function imgPromise(index, imgNode) { 
     return $.Deferred(function(dfrd) { 
      $("<img/>").on('load error', dfrd.resolve).attr('src', imgNode.src); 
     }).promise(); 
    } 
    var promises = $("#ajaxoutput").html(data).find("img").map(imgPromise); 
    return $.when.apply(null, promises); 
} 

chiamata come segue:

getData(table).then(display_result).then(equalise); 
+0

Grazie per il codice ben spiegato, ma la funzione equalize non viene chiamata quando provo questo. – CodingCodger

+0

Quanto lontano arriva? Cosa significa per esempio 'console.log (promises.length)'? –

+0

Whoops, ho ottenuto la firma della callback '.map()' di jQuery errata. Una riga modificata sopra. –

Problemi correlati