4

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.

asked Jan 16, 2014 at 21:52
3
  • 3
    Welcome to the wonderful world of async! You can't do that. Instead, use callbacks or promises. Commented Jan 16, 2014 at 21:54
  • @SLaks do you mean mean something like AJAX? Commented Jan 16, 2014 at 21:55
  • 2
    var answer = prompt("some question")...? Commented Jan 16, 2014 at 21:57

2 Answers 2

2

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.

answered Jan 16, 2014 at 23:06
Sign up to request clarification or add additional context in comments.

Comments

0

window.prompt("sometext","defaultText");

From: http://www.w3schools.com/js/js_popup.asp

answered Jan 16, 2014 at 22:20

1 Comment

sorry, I thought not wanting to use confirm implied not wanting to use alert or prompt either. edited original question

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.