2013-01-18 9 views
21

Ho un ciclo for I looping.Attendere la richiamata prima di continuare per il ciclo

Desidero creare una modal personalizzata e attendere una risposta prima di continuare.

Come posso ottenere questo risultato? So che devo aspettare una richiamata.

come in questo esempio:

for(var x in array){ 
      alert(x); 
      console.log(x); 
     } 

Fa esattamente quello che voglio. Ma voglio avere tre pulsanti. Ma l'avviso non fa parte di javascript (? È nel browser.)

Quindi, avete un'idea?

Stavo pensando di fare qualcosa di simile:

var run = true; 
function foo(){ 
    if (run){ 
     setTimeout(foo, 500); 
    } 
} 

function stop(){ 
    run = false; 
} 

foo(); 

e quindi attendere per una sosta, che invita un clic del pulsante prima di continuare. Ma questa è davvero una buona pratica?

Oppure utilizzare una funzione lambda come parametro per CustomAlert e una variabile "globale" che mantiene la posizione corrente dell'array che sto attraversando e lo fa con le funzioni. Come: Controllare se matrice è ancora in mano le chiavi superiori X. quindi effettuare la funzione di nuovo e ogni volta che aumentano la X. globale

Grazie lostsource per il codice: Oh, mi è venuta un'idea; Userò semplicemente la soluzione di lostsource all'interno di una funzione anonima, quindi non otterrò variabili globali. Eccellente.

(function(){ 

})(); 
+0

Stai dicendo che non puoi effettivamente usare l'avviso perché non supporta abbastanza opzioni? –

+0

Non è possibile semplicemente sostituire 'alert()' con una modal personalizzata e farlo funzionare allo stesso modo in cui l'avviso è –

+0

'alert's è BTW sincrono. Non sarai in grado di fermare un'esecuzione di una funzione del genere - a meno che non usi le coroutine/['yield'] di JS1.7 (https://developer.mozilla.org/en-US/docs/JavaScript/New_in_JavaScript/1.7#Generators) ma non è molto cross-browser e richiede la definizione di una 'versione' sul tuo tipo di script. Probabilmente dovresti archiviare il 'i' all'interno di un contesto di esecuzione e passarlo a una funzione che esegue un'ulteriore iterazione che richiama il tuo avviso di stile che ancora una volta passa indietro di un' i alla tua funzione iteratore. –

risposta

61

Supponendo che questo è l'array

var list = ['one','two','three']; 

Puoi provare a utilizzare questo approccio ciclo/callback

var x = 0; 
var loopArray = function(arr) { 
    customAlert(arr[x],function(){ 
     // set x to next item 
     x++; 

     // any more items in array? continue loop 
     if(x < arr.length) { 
      loopArray(arr); 
     } 
    }); 
} 

function customAlert(msg,callback) { 
    // code to show your custom alert 
    // in this case its just a console log 
    console.log(msg); 

    // do callback when ready 
    callback(); 
} 

Usage:

// start 'loop' 
loopArray(list); 

JSFiddle qui: http://jsfiddle.net/D9AXp/

+0

Sì, ho avuto un'idea del genere (sull'utilizzo di una funzione lambda) :) Grazie mille. – Muqito

+3

Estremamente utile grazie, fantastico ho appena usato arr.lenght-1 – Bakly

+0

In realtà, non penso che funzioni se il callback deve fare qualcosa in modo asincrono. Si prega di verificare questo, mi piacerebbe sapere se c'è una soluzione per questo, come sto cercando di caricare i file di immagine uno per uno che richiedono un po 'di tempo ciascuno: https://jsfiddle.net/evejweinberg/tydfbop6/1/ – EJW

2

MaggiQall, so che hai una risposta, ma ho una soluzione flessibile che potrebbe interessarti o forse a qualcun altro.

La soluzione dipende da jQuery (1.7+) e dall'interfaccia utente jQuery dialog, ma viene implementata come metodo personalizzato del prototipo Array, non come un plug-in jQuery.

Ecco il metodo Array:

Array.prototype.runDialogSequence = function(dialogCallback, startIndex, endIndex){ 
    startIndex = Math.max(0, startIndex || 0); 
    endIndex = Math.min(this.length - 1, endIndex || this.length - 1); 
    var sequenceIndex = 0, 
     arr = this, 
     dfrd = $.Deferred().resolve(startIndex); 
    function makeCloseFn(seqData){ 
     return function(event, ui){ 
      if(seqData.continue_) { seqData.dfrd.resolve(seqData.arrayIndex+1, seqData); } //continue dialog sequence 
      else { seqData.dfrd.reject(seqData.arrayIndex, seqData); } //break dialog sequence 
     } 
    } 
    $.each(this, function(i){ 
     if(i < startIndex || i > endIndex) { return true; }//continue 
     dfrd = dfrd.then(function(arrayIndex){ 
      var seqData = { 
       dfrd: $.Deferred(), 
       arrayIndex: arrayIndex, 
       sequenceIndex: ++sequenceIndex, 
       length: 1 + endIndex - startIndex, 
       item: arr[arrayIndex], 
       continue_: false 
      }; 
      dialogCallback(seqData).on("dialogclose", makeCloseFn(seqData)); 
      return seqData.dfrd.promise(); 
     }); 
    }); 
    return dfrd.promise(); 
} 

Array.runDialogSequence() si basa su:

  • Un modello di dialogo nel corpo del documento, in forma per essere popolato con testo/valori.
  • un array di elementi simili (in genere oggetti javascript) contenenti i dati necessari per compilare la finestra di dialogo, in sequenza.
  • passando, come primo argomento, una funzione "openDialog" correttamente costruita.

Ecco un esempio funzione "OpenDialog" con commenti esplicativi:

function openDialog(seqData){ 
    /* 
    seqData is an object with the following properties: 
     dfrd: A Deferred object associated with the current dialog. Normally resolved by Array.runDialogSequence() to run through the sequence or rejected to break it, but can be resolved/rejected here to force the dialog sequence to continue/break. If resolved, then pass (seqData.arrayIndex+1, seqData), or custom values. If rejected, typically pass (seqData.arrayIndex, seqData). 
     arrayIndex: The current array index. 
     sequenceIndex: The current index within the sequence. Normally the same as arrayIndex but Differs when a non-zero startIndex is specified. 
     length: The full length of the dialog sequence. 
     item: The current item from the array. 
     continue_: (false) Set to true to allow the sequence to continue. 
    */ 
    var item = seqData.item; 
    var $d = $("#d"); 
    $d.dialog({ 
     title: 'Dialog (' + seqData.sequenceIndex + ' of ' + seqData.length + ')', 
     modal: true, 
     buttons: { 
      "Continue": function(){ 
       seqData.continue_ = true;//set to true before closing to go to next dialog. 
       $(this).dialog("close"); 
      }, 
      "Cancel": function(){ 
       $(this).dialog('close');//closing with seqData.continue_ set to its default value false will break the dialog sequence. 
      } 
     } 
    }).find("#message").text(item);//Typically you will do a lot more here to populate the dialog with item data. 
    return $d;//openDialog() must return a dialog container, jQuery-wrapped. 
} 

Array.runDialogSequence() restituisce un jQuery promise, permettendo azioni personalizzate da eseguire quando la sequenza di dialogo completa (funzione fatto) o è rotto a metà -sequence (fail function).

Qui ci sono un paio di chiamate di esempio:

//Simplest possible 
$("#myButton1").click(function(){ 
    myArray.runDialogSequence(openDialog); 
}); 

//Call with custom startIndex and endIndex, and chanined `.then()` to provide custom actions on break/completion. 
$("#myButton2").click(function(){ 
    myArray.runDialogSequence(openDialog, 1, 3).then(function(i, seqData){ 
     alert('All dialogs complete - last item = "' + seqData.item + '"'); 
    }, function(i, seqData){ 
     alert('Dialog sequence was broken at item ' + i + ' "' + seqData.item + '"'); 
    }); 
}); 

DEMO

Questo è il più vicino ad una soluzione generalizzata come la mia immaginazione consente.

+0

Questo è stato davvero neet, ti ho dato un upvote atleast :) – Muqito

+0

Grazie a MaggiQall, sarà interessante vedere se qualcuno lo trova utile in futuro. –

Problemi correlati