MikeMichaels
MikeMichaels

Reputation: 494

Javascript - how to use the same onkeydown event to call different functions on different occasions

I am trying to make a simple quizz with random questions. After typing in the answer, the user can press the Enter key to check whether his answer is correct or wrong. In that moment the textbox will be hidden.

I would like the user to be able to press the Enter key again to proceed to the next question. But how can I do that, since I already have a function being called with that key?

This is what I am working with:

    var country = ["Italy", "Spain", "Portugal", "France"];
    var capital = ["rome", "madrid", "lisbon", "paris"];
    var random001 = Math.floor(Math.random() * country.length);

    document.getElementById("country").innerHTML = country[random001];

    function submit001() {
        var b = input001.value.toLowerCase();
        var text;
        switch (true) {
            case random001 == 0 && b == capital[0]:
            case random001 == 1 && b == capital[1]:
            case random001 == 2 && b == capital[2]:
            case random001 == 3 && b == capital[3]:
                text = "Correct!";
                hideAndShowDIV();
                break;
            default:
                text = input001.value.bold() + " is not correct!";
                document.getElementById("input001").value = "";
        }
        document.getElementById("answer001").innerHTML = text;
    }

    function hideAndShowDIV() {
        var x = document.getElementById("userInput");
        if (x.style.display === "none") {
            x.style.display = "block";
        } else {
            x.style.display = "none";
        }
    }

    function goToNextQuestion() {
        random001 = Math.floor(Math.random() * country.length);
        document.getElementById("country").innerHTML = country[random001];
        hideAndShowDIV()
        document.getElementById("input001").focus();
    }
    <p id="message001">What is the capital of <text id="country"></text>?</p>
    <div id="userInput" style="display:block">
        <input type="text" id="input001" autofocus onKeyDown="if(event.keyCode==13) submit001();">
    </div>
    <p id="answer001"></p>

The function goToNextQuestion() is what I want to call with the Enter key.

Upvotes: 0

Views: 826

Answers (4)

talemyn
talemyn

Reputation: 7950

Without going into too much detail (I'd have to understand a lot more about the behavior that you would want in various scenarios . . . Example: Can the user go back to a previous question, change the answer, and revalidate?), I'd suggest some kind of indicator attached to or associated with (i.e., on a close ancestor element) the input to track whether or not an answer has been validated yet.

For example, you could us a class (e.g., class="answer-validated") or a data attribute (e.g., data-validated="true") if the user has already hit Enter to check the value. In the case of a class, it would be absent by default and the "validation" code would add it as part of its logic. Similarly, the data attribute could default to "false" and be updated to "true" when the answer is validated.

The benefit of this approach is that it allows you to directly control the tracking of the input state and, potentially reuse it for other functionality, including:

  • resetting the input state, if the user wants to re-answer,
  • easily resetting the state of all questions, without having to refresh/reset the page
  • applying visual differences with CSS, based on the presence of the class or state of the data attribute
  • track the number of answers that have been checked and place a limit on the maximum number of validations (i.e., "You can only check 3 answers before submitting your answers")
  • Etc.

It's possible to infer the state from other elements on the page, but I would argue that it would make more sense to manage the state of the input on itself, rather than determining it based on the state of another page element. It's more straightforward and less prone to having changes to the other elements impact the functionality of the input.

Upvotes: 0

trincot
trincot

Reputation: 350202

A quick solution would be to add an extra line in the function submit001, before any of the code it already has:

if (document.getElementById("answer001").textContent === "Correct") {
    goToNextQuestion();
}

And in the function gotoNextQuestion you should then make sure to clear that text content (remove "Correct").

But be aware the the keydown event does not trigger on the input element when you hide it, so you should listen to that event on the document.

Better still would be to use a variable for that state, instead of depending on what is in the HTML document.

Here is an implementation that uses addEventListener instead of having JS code inside your HTML tags. Note how it listens on the document level. Also better to use the event key property and not keyCode.

A new variable execOnEnter defines which function to execute depending on the state of the "game". It is changed in the code to either submit001 or goToNextQuestion:

var country = ["Italy", "Spain", "Portugal", "France"];
var capital = ["rome", "madrid", "lisbon", "paris"];
var random001 = Math.floor(Math.random() * country.length);

document.getElementById("country").textContent = country[random001];

var execOnEnter = submit001;
document.addEventListener("keydown", function (e) {
    if (e.key !== "Enter") return;
    execOnEnter();
});

function submit001() {
    var b = input001.value.toLowerCase();
    var text;
    if (b === capital[random001]) {
        text = "Correct!";
        hideAndShowDIV();
        execOnEnter = goToNextQuestion;
    } else {
        text = input001.value.bold() + " is not correct!";
    }
    document.getElementById("input001").value = "";
    document.getElementById("answer001").innerHTML = text;
}

function hideAndShowDIV() {
    var x = document.getElementById("userInput");
    if (x.style.display === "none") {
        x.style.display = "block";
    } else {
        x.style.display = "none";
    }
}

function goToNextQuestion() {
    document.getElementById("answer001").innerHTML = "";
    random001 = Math.floor(Math.random() * country.length);
    document.getElementById("country").innerHTML = country[random001];
    hideAndShowDIV()
    execOnEnter = submit001;
    document.getElementById("input001").focus();
}
<p id="message001">What is the capital of <text id="country"></text>?</p>
<div id="userInput" style="display:block">
    <input type="text" id="input001" autofocus>
</div>
<p id="answer001"></p>

Upvotes: 1

bPuhnk
bPuhnk

Reputation: 385

There are a few ways you could do this. I would recommend not using this approach though, as hitting the enter button to submit is not intuitive. I would recommend adding a 'submit' button. Regardless you could try this:

        
        var country = ["Italy", "Spain", "Portugal", "France"];
        var capital = ["rome", "madrid", "lisbon", "paris"];
        var random001 = Math.floor(Math.random() * country.length);

        document.getElementById("country").innerHTML = country[random001];

        function input001_onKeyDown(e){
          if(e.keyCode === 13){
            submit001();
          } else {
            clearParagraph();
          }
        }

        function submit001() {

            var b = input001.value.toLowerCase();
            document.querySelector("#input001").value = ''
            var text;
            switch (true) {
                case random001 == 0 && b == capital[0]:
                case random001 == 1 && b == capital[1]:
                case random001 == 2 && b == capital[2]:
                case random001 == 3 && b == capital[3]:
                    text = "Correct! " + b + " is the capital of " + country[random001];
                    goToNextQuestion();
                    break;
                default:
                    text = b + " is not correct!";
                    document.getElementById("input001").value = "";
            }
            document.getElementById("answer001").innerHTML = text
        }

        function hideAndShowDIV() {
            var x = document.getElementById("userInput");
            if (x.style.display === "none") {
                x.style.display = "block";
            } else {
                x.style.display = "none";
            }
        }

        function goToNextQuestion() {
            random001 = Math.floor(Math.random() * country.length);
            document.getElementById("country").innerHTML = country[random001];
            document.getElementById("input001").focus();
        }

        function clearParagraph(){
          document.querySelector("#answer001").innerHTML = ''
        }
    <p id="message001">What is the capital of <text id="country"></text>?</p>
    <div id="userInput" style="display:block">
        <input type="text" id="input001" autofocus onKeyDown="input001_onKeyDown(event)">
    </div>
    <p id="answer001"></p>

Upvotes: 0

Marc M.
Marc M.

Reputation: 174

You could check inside the the submit001() function to check if the userInput control is hidden and if so, direct go to the goToNextQuestion.

Upvotes: 0

Related Questions