54

When I write alert('Hello'), the page execution stops and waits for approval to continue.

I have a div setup to display as a fake alert, using HTML - this div has an 'OK' button.

I want the page to stop its execution (just like alert does) until the user click 'OK'.

Is it possible ?

Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • 1
    It's possible with Promise API. – codef0rmer Jan 04 '15 at 07:31
  • just what i looked for, sometime you need to stop it totally. i hope i doesn't use while loop :D i mean stopping the process without using any resource consuming code... – Hassan Faghihi Jan 04 '16 at 06:23
  • 1
    @Vixed: What's out of date about the current answers? That they don't mention promises? Or the upcoming await/async (the semantics of which are still not nailed down)? – T.J. Crowder Apr 04 '16 at 12:04
  • must be another way @T.J.Crowder i need to **run code; --> custom alert --> break; go on;** can't write a callback anytime I need an alert. – Vixed Apr 04 '16 at 12:07
  • @codef0rmer: *"It's possible with Promise API"* No, it isn't. Promises just let you write the callbacks differently, they don't let you stop the world like `alert` does. Promises are great, particularly when you need to compose or chain multiple promises, but they don't do what Royi asked for. – T.J. Crowder Apr 04 '16 at 12:08
  • @Vixed: Sorry, you simply can't do that with JavaScript on a browser. – T.J. Crowder Apr 04 '16 at 12:08
  • @T.J.Crowder **can't** is not in my dictionary. – Vixed Apr 04 '16 at 12:11
  • 4
    @Vixed: `dictionary.add("can't")` then. :-) Just like you can't jump over the Eiffel tower completely unaided, you can't change the fundamental nature of how browers run JavaScript code. Async operations, and callbacks (boring old-fashioned ones or ones associated with promises), are (for now) a fundamental part of JavaScript code. – T.J. Crowder Apr 04 '16 at 12:13
  • @Vixed Not possible to stop execution like an `alert`. `callback` is the only work around to go. The existing answer details this clearly and there simply isn't any other function like an alert in JavaScript. – Selvakumar Arumugam Apr 07 '16 at 13:37
  • @Vixed _"i need to run code; --> custom alert --> break; go on;"_ Can you create a jsfiddle http://jsfiddle.net or plnkr http://plnkr.co to demonstrate what you are trying to achieve? Do you mean break a loop? – guest271314 Apr 07 '16 at 15:15

8 Answers8

45

You can't. Only the special built-ins can do that. For a while there was the showModalDialog special built-in that let you specify a URI for the content and thus customize it, but it was never widely supported and is now deprecated even by browsers that once supported it.

Instead, make your current alerting function that uses the div accept a callback for when the alert is closed (or return a promise that's settled when it's closed), to allow you to continue processing.

So for instance, if your code used to use alert and work like this:

function foo() {
    var x;

    x = doSomething();
    alert("Alert! Alert!");
    doSomethingAfterTheAlertIsCleared(x);
    doAnotherThingAfterward();
}

...you'd change it to:

function foo() {
    var x;

    x = doSomething();
    fakeAlert("Alert! Alert!", function() {
        doSomethingAfterTheAlertIsCleared(x);
        doAnotherThingAfterward();
    });
}

Note that now all the code that followed the alert is in a function, whose reference we pass into the fakeAlert. The foo function returns while the fake alert is still showing, but eventually the user dismisses the fake alert and our callback gets called. Note that our callback code has access to the locals in the call to foo that we were processing, because our callback is a closure (don't worry if that's a fairly new and/or mysterious term, closures are not complicated).

Of course, if the only thing following the alert is a single function call that doesn't take any arguments, we could just pass that function reference directly. E.g., this:

function foo() {
    doSomething();
    alert("Alert! Alert!");
    doSomethingAfterTheAlertIsCleared();
}

becomes:

function foo() {
    doSomething();
    fakeAlert("Alert! Alert!", doSomethingAfterTheAlertIsCleared);
}

(Note that there are no () after doSomethingAfterTheAlertIsCleared -- we're referring to the function object, not calling the function; fakeAlert will call it.)

In case you're not sure how fakeAlert would call the callback, it would be within the event handler for the user "closing" the alert div, and you just call the argument for the callback just like you do with any other reference to a function. So if fakeAlert receives it as callback, you call it by saying callback();.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 2
    Just for fun I tried to 'hack' the alert/confirm dialogs and, even if I didn't succeed, I did notice that, in Chrome at least, one can check a box and prevent the window from creating additional modal dialogs. So even if somehow someone would replicate the same behaviour, it would still not be enough. This solution is the way to do it. – Siderite Zackwehdex Apr 08 '16 at 04:42
  • btw. you can stop `throw new FatalError("!! Stop JavaScript Execution !!");` – john Smith Oct 01 '20 at 07:37
  • @johnSmith - That doesn't do what the OP is trying to do, it just terminates the function. – T.J. Crowder Oct 01 '20 at 08:20
  • what's fakeAlert? – Shivam Sahil Jan 14 '22 at 16:42
  • 1
    @ShivamSahil - It's the function that the OP would write to *"...make [their] current alerting function that uses the `div` accept a callback for when the alert is closed (or return a promise that's settled when it's closed), to allow [them] to continue processing."* – T.J. Crowder Jan 14 '22 at 16:59
10

Yes it's possible, i did inaccurate and not very well tested demo which does this.

Main concept:

  1. in this example we have method Login.Try() which is executing Login.Proceed() method. Login.Proceed() makes AJAX query and we would like to wait for its execution, but don't want bind any handlers (just wait for it as window.alert() does)
  2. instead of direct function's execution Login.Proceed, we use async() and await() methods (like in C#)
  3. when we need to "pause" script and wait for something, we stop method execution using throw, and parse caller's function, to run its second part when waited (async) method has completed its execution.

What was left out of scope:

  1. Clean code
  2. Test solution for different browsers
  3. Save/Restore local variables
  4. Not works for loops.

Demo:

<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>

<script>

Login.Try(); // START!! START!! START!!

var Login = {
    Url: "http://xxxx",
    Try: async(this, function (T) {

        console.log('before login');

        //var success = call(this, Login.Proceed); // normal call
        var success = await(this, Login.Proceed);  // that we want!

        console.log('after login');
        console.log('success ' + success);

    }),

    Proceed: function (callback) {
        console.log('before ajax');
        $.ajax({
            url: this.Url,
            context: document.body
        }).done(function () {
            console.log('after ajax');
            callback("role=admin");
        });
    }
}


function async(T, method){
   console.log('before async create');
   return function () { return method.apply(T); };
   console.log('after async create');
};

function await(T, method) {
    var fn = arguments.callee.caller.toString();
    var pos = fn.indexOf('await(');
    var allBeforeAwait = fn.substring(0, pos);

    var pos1 = fn.indexOf('await(');
    pos1 = fn.indexOf(',', pos1) + 1;
    var pos2 = fn.indexOf(')', pos1);
    var cc = fn.substring(pos1, pos2);


    pos = allBeforeAwait.lastIndexOf(';');
    var allBeforeCall = allBeforeAwait.substring(0, pos + 1) + "}";
    var callResult = allBeforeAwait.substring(pos + 1);

    var result = 10;
    var allAfterCall = "("+fn.substring(0, fn.indexOf(")")) + ",V){" + callResult + "V;";
    pos = fn.indexOf(')', pos) + 2;
    allAfterCall = allAfterCall + fn.substring(pos)+")";

    //uncomment to see function's parts after split
    //console.debug(allBeforeCall);
    //console.debug(cc);
    //console.debug(allAfterCall);

    method.apply(T, [function (value) {
        console.log('ajax response ' + value);
        eval(allAfterCall).apply(T, [T, value]);
    } ]);

    throw "";
};

</script>

Hope this demo will inspire you with some ideas.

Also, you can take a look on http://blogs.msdn.com/b/rbuckton/archive/2011/08/15/promise-js-2-0-promise-framework-for-javascript.aspx

Vlad Mysla
  • 1,181
  • 12
  • 15
  • Can you please upload jsfiddle ? – Royi Namir May 26 '13 at 13:28
  • 1
    Sure - http://jsfiddle.net/vmysla/g3MzL/ Feel free to play with it. Script logs into browser's console most of actions – Vlad Mysla Jul 02 '13 at 16:13
  • fiddle throw errors on chrome, i didn't test other browsers... console log: before ajax (index):108 Uncaught await @ (index):108(anonymous function) @ (index):52(anonymous function) @ (index):74onclick @ (index):118 (index):65 after ajax (index):104 ajax response role=admin VM498:4 after login VM498:5 success role=admin – Hassan Faghihi Jan 04 '16 at 06:37
  • 1
    hi @deadManN, thanks! I fixed that error. try now. you can open the console and see what happens – Vlad Mysla Jan 09 '16 at 05:41
  • my whole os crashed, if i remind it, and i had nothing to do, sure i'll check, thanks – Hassan Faghihi Jan 09 '16 at 09:33
  • I like the approach, yet somehow having a script processor implemented in Javascript feels like overkill just for this. What I would see as a working solution - regardless of how complicated it would be - is to implement it as a script type, something like script type="text/fixeruper" and then a separate processor translate it into Javascript. See here: http://james.padolsey.com/cool-stuff/custom-javascript-with-parsescripts/ – Siderite Zackwehdex Apr 08 '16 at 04:49
1

You can use following code to pause execution for long period of time.

function PauseExcecution() {
//Do some stuff
sleep(1000);
//Do some stuff...

}

function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}
Jasmeen
  • 876
  • 9
  • 16
  • 1
    You could also use Infinity https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity – kurdtpage Jun 08 '21 at 03:08
0

It's not possible like the alert, but you can make things to look like an alert.

For example you make a function which calls functions. :) Then you make a function with a huge IF.

window.callfunction = function (f, a, b) /* function name, arguments, boolean*/
{
    var handler = window[f];
    if (typeof handler === 'function') {
        handler(a, b);
    } else {
        alert("No function like that mate, sry.");
    }
}

function deleteAfterConfirm(a, b) /* arguments, boolean */
{
    if (b == true) {
        alert("i can delete, confirmed.");
        alert(a);
        return false;
    }
    magicConfirm(a);
}

function magicConfirm(a) {
    /** 
        modals, popovers, etc, anything you want,
    **/
    $("#confirmModal").modal("show");
    /**
        and put the function's name to the binding element's data
    **/
    $("#returntrue").data("call", arguments.callee.caller.name);
    $("#returntrue").data("arguments", a);
    /** 
        the element like OK button in the alert 
        calls the magicConfirm function's caller function 
        with true, which is the deleteAfterConfirm, and 
        because the bool is true, it will alert i can delete... 
    **/
    $("#returntrue").bind("click", function () {
        callfunction($(this).data("call"), $(this).data("arguments"), true);
    });
}


$(document).ready(function () {
    $("#deleteAfterConfirm").on("click", function () {
        deleteAfterConfirm("variable which is needed later.");
    });
});

So now you can use the deleteAfterConfirm function like a function with alert() or confirm(), because it's recalling the other part if itself.

Not the best method, but this can somehow replace the confirms and alerts for a better looking version. This is a way of the fake alertism :)

Have fun - R

Répás
  • 1,812
  • 7
  • 28
  • 54
0

You can do it with Promise API. This is just about dividing your code and placing some lines in an action listener. Here is the sample code:

In this example, there are two buttons. Clicking first button starts a code and the rest of your code will be placed on promise.then function.

Html Code:

<body>
  <button id='startButton' onclick='start();'>Start Button</button>
  <button id='targetButton'>Target Button</button>
</body>

Script Code:

<script>
    function start(){
      console.log('first log'); //put your div displayer code here
      let promise = new Promise(function(resolve, reject) {
          console.log('promise started');
          let targetButton = document.getElementById('targetButton');
          targetButton.addEventListener("click",function(){
            resolve();
          });
      });
      promise.then(function() {
          console.log('second log'); //put the rest of your code
      });
    }
</script>

You will see first log and promise started just after triggering start button. second log will be displayed after you click the target button.

The resources for Promise API:

ykaragol
  • 6,139
  • 3
  • 29
  • 56
  • This doesn't stop the execution of Javascript the way `alert` does. – Flimm May 23 '20 at 21:22
  • @Flimm, that's impossible. as accepted answer described. This answer shows a way to stop the flow and resume it whenever a user action happens. – ykaragol May 29 '20 at 10:01
0

If you want to wait for the dialog box to close, the "open" property indicates whether the dialog box is open or closed. When it's done, resolve the promise. For synchronization, add a timer to periodically test this property.

    let d = document.querySelector('dialog')
    d.showModal()
    await new Promise((resolve, reject) => {
        let timer = setInterval(_ => {
            if (!d.open) {
                resolve()
                clearInterval(timer)
            }
        }, 500)
    })
user1587368
  • 314
  • 2
  • 6
-2

I think this is possible using basic JavaScript. You could have the fake button set like this:

<button id="fakeButton" value="not" onclick="fakeButtonValChange()">OK</button>

Then:

function fakeButtonValChange() {
var fakebuttonval = document.getElementById("fakeButton").value;
document.getElementById("fakebutton").value = 
"clicked"
if (fakebuttonval == "clicked") {
*place stuff to show div here (i'm not good with css and that stuff)*
}
KingK
  • 34
  • 8
-2

Use `Bootstap' modal

Then remove close button and disable model window hide by using below code

$('#myModal').modal({backdrop: 'static', keyboard: false})

Bind your function and close event to OK button of that modal window.

Apoorv
  • 231
  • 1
  • 8