I've a for-loop I'm looping through.
I want to make a custom modal and wait for a response before continue it.
How can I achieve this? I know I've to wait for a callback.
Like this example:
for(var x in array){ alert(x); console.log(x); }
It does exactly what I want to. But I want to have three buttons. But alert is not part of javascript(? It's in the browser.)
So, do you guys have an idea?
I was thinking about doing something like this:
var run = true; function foo(){ if (run){ setTimeout(foo, 500); } } function stop(){ run = false; } foo();
and then wait for a stop which calls on a button click before continue. But is this really good practice?
Or use a lambda function as a parameter to the customAlert and a "global" variable that holds the current position of the array I'm going through and do this with functions. Like: Check if array is still holding keys greater than X. Then do the function again and each time increase the global X.
Thank you lostsource for the code: Oh, I got an idea; I'll simply use lostsource's solution inside an anonymous function, so I don't get global variables. Excellent.
(function(){ })();
The Solution—Async/Await Your loop needs to wait for the asynchronous task to complete on each round of the for loop. To make this happen, mark your function asynchronous using the async keyword, and place an await keyword in front of the action you want to wait for.
Callbacks are also closures as the passed function is executed inside other function just as if the callback were defined in the containing function.
Wait for function to finish using async/await keywords As you already know from the Promise explanation above, you need to chain the call to the function that returns a Promise using then/catch functions. The await keyword allows you to wait until the Promise object is resolved or rejected: await first(); second();
The standard way of creating a delay in JavaScript is to use its setTimeout method. For example: console.log("Hello"); setTimeout(() => { console.log("World!"); }, 5000); This would log “Hello” to the console, then make JavaScript wait 5 seconds, then log “World!”
Assuming this is your array
var list = ['one','two','three'];
You can try using this loop / callback approach
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 here: http://jsfiddle.net/D9AXp/
MaggiQall, I know you have an answer but I have a flexible solution that may be of interest to you or maybe to someone else.
The solution depends on jQuery (1.7+) and jQuery UI's dialog
, but is implemented as a custom method of the Array prototype, not as a jQuery plugin.
Here's the Array method :
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()
relies on :
Here's a sample "openDialog" function with explanatory comments :
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()
returns a jQuery promise
, allowing custom actions to be performed when the dialog sequence completes (done function) or is broken in mid-sequence (fail function).
Here are a couple of sample calls :
//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
This is as close to a generalized solution as my imagination allows.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With