Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pause JavaScript until input, like a confirm/alert box?

Tags:

javascript

I have a game, and at certain points I need to prompt the user.

For one question, it's simple. I place an overlay over everything else, and have a yes and no button. I change the actions of the buttons depending on the question, but in some cases I need to ask 2 or 3 questions. By using confirm() I could just put this in a for loop, but at the moment it will just change the questions and answers.

I was thinking to set a variable like numberOfQs = 3 and then currentQ = 1 and after the yes/no button is clicked I increment and call a question function until currentQ === numberOfQs

Is that the best/only option? I don't want to use confirm() or prompt() because I can't style it.

No JS library answers please.

like image 303
cantsay Avatar asked Feb 21 '26 06:02

cantsay


1 Answers

Problem

How can I pause JavaScript until input, like a confirm/alert box?

Simple answer is: you can't (if styling is required).

JS is asynchronous and single-threaded so there is no way to prevent running the code as all "inputs" (DOM buttons, input fields etc.) are asynchronous in nature (ie. by using an event queue). Doing a busy-loop (for/while) for polling would simply block the thread so you couldn't check events and polling using for example setTimeout would make it asynchronous again.

You can use prompt() (not style-able but blocks the browser as you intend) or use an overlay as you already do and handle events the way JS was designed for. Flags are useful here to block UX (ghosting/disabling-wise) while waiting for a condition to be fulfilled. It's all about program design.

If you already have an overlay simply replace the question text with the next until there are no more and then remove the overlay. You can embed this into an object that handles the buttons and text for you.

Solution

Creating objects that are self-contained makes this a walk in the park.

Lets create two objects:

  1. Poll master
  2. A Question object.

The Poll object will setup the overlay and remove it when done as well as call our callback.

The Question object will setup the question text, buttons and handle the button clicks and answer.

Online demo here

The Poll object looks like this:

function Poll(callback) {

    var overlay = document.createElement('div'), /// overlay DIV

        current,      /// question counter
        me = this;    /// self-reference

    /// question array
    this.questions = [];

    /// setup overlay div with classname
    overlay.className = 'overlay';

    /// method to add questions
    this.add = function(q) {
        me.questions.push(q);
    }

    /// start the poll
    this.start = function() {

        if (me.questions.length === 0) return;

        /// inject the overlay to DOM            
        document.body.appendChild(overlay);

        /// start the displaying of questions
        current = 0;
        next();
    }

    /// called from question itself as well as a callback
    function next() {
        if (current < me.questions.length) {

            /// provide overlay (parent) and callback
            me.questions[current].show(overlay, next);
            current++;

        } else {
            /// when done, remove overlay and callback
            document.body.removeChild(overlay);
            callback();
        }
    }
}

Not so complicated: it keeps a mechanism to add question objects, start the poll and go to next question.

The Question object looks like this:

function Question(txt) {

    /// create the various elements we need
    var box = document.createElement('div'),
        btnYes = document.createElement('button'),
        btnNo = document.createElement('button'),
        me = this;

    /// setup question box with text and class name
    box.className = 'question';
    box.innerHTML = txt;

    /// setup buttons with text, classes and event handlers
    btnYes.className = 'buttonYes';
    btnNo.className = 'buttonNo';
    btnYes.innerHTML = 'YES';
    btnNo.innerHTML = 'NO';

    /// add the buttons to question box
    box.appendChild(btnYes);
    box.appendChild(btnNo);

    btnYes.onclick = handleYes;
    btnNo.onclick = handleNo;

    /// expose question and answer
    this.question = txt;
    this.answer = null;

    /// called from Poll object to show question
    this.show = function(parent, callback) {
        me.parent = parent;
        me.callback = callback;

        /// add question box to overlay
        parent.appendChild(box);
    }

    /// if we clicked "yes", set answer and remove box
    function handleYes() {
        me.answer = true;
        done();
    }

    /// if we clicked "no", set answer and remove box
    function handleNo() {
        me.answer = false;
        done();
    }

    function done() {
        /// remove box and call "next()" in Poll object
        me.parent.removeChild(box);
        me.callback(me.answer);
    }
}

Usage

Now when these objects are in place we simply setup a poll like this:

var poll = new Poll(done);

poll.add(new Question('This will work fine?'));
poll.add(new Question('This is second question?'));
poll.add(new Question('This is third question?'));

poll.start();

And that's it. All we need to do now is to define the CSS rules for the classes we added.

We can also iterate the question objects as well to see what we answered:

function done() {
    for(var i = 0, q; q = poll.questions[i]; i++)
        console.log(q.question, q.answer);
}

Hope this helps.


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!