1

I am creating a quiz game, but I only want the user to be able to submit if all of the input fields are filled out using only JavaScript. I saw other similar questions on StackOverflow that used jquery, but I want to only use JavaScript.

html (Django template)


    <h1 class="all_headings" id="quiz_title">{{ quiz.title }}</h1>
        <h4 class="quiz_description">By: {{ quiz.user }}</h4>
        <h4 class="quiz_description">Created On: {{ quiz.date_and_time }}</h4>
        <br>
    
        {% for q in quiz_questions %}
            <h3 class="quiz_questions">{{q.1}}
                <input type="text" id="id_question{{q.0}}" class="input">
            </h3>
            <div id="div{{ q.0 }}"></div>
            <br>
            <br>
        {% endfor %}
        <input type="submit" value="Submit" class="button quiz_button" id="{{ quiz.id }}"> 
     
        <h2 id="score"></h2>
        <input type="hidden" id="user_id" value="{{ request.user.id }}">
        <input type="hidden" id="user_points" value="{{ request.user.points }}">
        {% if request.user.is_anonymous %}
            <h3 class="all_headings"><a href="{% url 'register' %}">Join now</a> to earn 10 points for every question you answer correctly!</h3>
        {% endif %}

Update: I added the entire Django template code so that you can see what is going on.

current JavaScript

function bindText(e){
    const required = [...document.querySelectorAll(".inputs")];
    required.forEach(input => input.oninput = checkText);
}

function checkText(e){
    const required = [...document.querySelectorAll(".inputs")];
    const button = document.getElementsByClassName(".quiz_button");
    button.disabled = !required.every(input => input.value.length > 0);
}



document.addEventListener('DOMContentLoaded', function(){
    //gets all the quiz_buttons                                                                                                                                        enableChecking();
    const quizButton = document.querySelectorAll('.quiz_button');
    for (const button of quizButton){
        button.addEventListener('click', (event) => check_quiz(event.target.id));
    }
})

function check_quiz(id){
    console.log("button is clicked");

    //get answers
    let response1 = document.getElementById('id_question1').value.toUpperCase().replace(/\s/g, "");
    let response2 = document.getElementById('id_question2').value.toUpperCase().replace(/\s/g, "");
    //repeats 8 more times

    //get divs
    let div1 = document.getElementById('div1');
    let div2 = document.getElementById('div2');
    //repeats 8 more times

    var correctAnswers = 0;

    //get quiz
    fetch(`/check/${id}`)
    .then(response => response.json())
    .then(quiz => {
        rightM = "You got this correct. Great job!";
        //checking if the answers are right
        //#1
        let answ1 = quiz.answer1.toUpperCase().replace(/\s/g, "");
        if(answ1 === response1){
            div1.innerHTML = rightM;
            div1.classList.add("correct"); 
            correctAnswers++;
        } else{
            div1.innerHTML = `The correct answer is ${quiz.answer1}. Nice try!`;
            div1.classList.add("incorrect");
        }
        //#2
        let answ2 = quiz.answer1.toUpperCase().replace(/\s/g, "");
        if(answ2 === response2){
            div2.innerHTML = rightM;
            div2.classList.add("correct");
            correctAnswers++;
        } else{
            div2.innerHTML = `The correct answer is ${quiz.answer2}. Nice try!`;
            div2.classList.add("incorrect");
        }
        //repeats 8 more times

        console.log(correctAnswers)
        //display score
        let score = document.getElementById("score");
        score.innerHTML = `Your score is ${correctAnswers}. Great job! :)`;
        score.classList.add("score_style");

         //points
        let newPoints = correctAnswers * 10;
        let currentUser = parseInt(document.getElementById("user_id").value);
        let currentPoints = parseInt(document.getElementById("user_points").value);

        let numOfPoints = currentPoints + newPoints;
        console.log(numOfPoints);

        fetch(`/points/${currentUser}`,{
            method: "PUT", 
            body: JSON.stringify({
                points: numOfPoints
            })
        })
    })
}

I updated this with my current code and fixed all the errors from Update 2 of the answer, but the submit button still does not work when it is pressed.

4
  • jQuery is JavaScript. Since you didn't post the jQuery code, I don't know which functions it contains, but maybe this link can help you: brcline.com/blog/how-to-replace-jquery-with-vanilla-javascript Commented Aug 4, 2022 at 23:15
  • @jabaa, I am not using jquery at all. Commented Aug 5, 2022 at 0:19
  • You wrote: "I saw other similar questions on StackOverflow that used jquery, but I want to only use JavaScript." The link describes how you can replace jQuey with Vanilla JS. Commented Aug 5, 2022 at 0:27
  • I can't continue on this question. There are more mistakes like using .inputs when it's supposed to be .input. If you were careful copying my code as well as your own, you would have working code. Example C solves your problem but you should really be careful about spelling things consistently and also use JSHint which catch mistakes like mismatching quotes ' " (which occurred more than once). What you need to understand is what events are. Commented Aug 10, 2022 at 2:53

1 Answer 1

1

Update 2

You need to go to JSHint and debug your code frequently. In Update 2 I have corrected as much as I care to. Before I can help you any further, you need to address the issues marked with a ❓.

Mark Description Corrected
There are 12 typos, even if there was only one ❌ it would FUBAR whatever follows it. Yes
There are 5 questionable areas which will most likely need to be addressed because it may cause problems later on, or is pointless, etc. No
🚩 Areas that could be modified to be more efficient, succinct, etc. No
Areas that are modified to be more efficient, succinct, etc. Yes

In Example D I placed where my code should go. There's always the chance that none of it may work because of Django. I have no idea, but on the surface it doesn't look debilitating.

Concerning <form>s, they are the the backbone of most interactive webpages but not necessary if you have other means such as fetch(). That is true in your case which means that you don't trigger "submit" events and you don't need a type="submit" unless there's something Django does that I'm ignorant to.

It isn't obvious to me how the HTML layout is exactly. I'm not certain whether there's one button (good) or multiple buttons (a very critical detail to know from the start).

Example D

document.addEventListener('DOMContentLoaded', bindText);

function bindText(e) {
  const required = [...document.querySelectorAll(".inputs")];
  required.forEach(input => input.oninput = checkText);
}

function checkText(e) {
  /*❌: = Does not belong at end of line */
  const required = [...document.querySelectorAll(".inputs")];
  /*❌: `${id}` NOT "${id}"|BUT `${id}` === id */
  /*❓: Is id declared elsewhere? If not, use it's actual "idOfButton". 
        If you have multiple submit buttons then you should reassess
        your strategy. 
  */
  const button = document.getElementById(id);
  /*❌: = missing */
  button.disabled = !required.every(input => input.value.length > 0);
}

/*❌: '...' or "..." NOT "...' */
document.addEventListener('DOMContentLoaded', function() {
  /*❌: = : ' missing */
  const quizButton = document.querySelectorAll('.quiz_button');
  for (const button of quizButton) {
    /*⭕: In event handlers/listeners if it is a named function that's
          defined separately, remove the ()
    */
    button.addEventListener('click', (event) => checkQuiz);
  }
});
/*⭕: Event handlers pass the (e)vent object by default */
function checkQuiz(e) {
  const id = e.target.id;
  /*❌: / missing a \ needs to be escaped: \\ */
  /*❌: response* number 1 NOT letter l */
  let response1 = document.getElementById('id_question1').value.toUpperCase().replace(/\\/g, "");
  /*❌: / missing a \ needs to be escaped: \\ */
  let response2 = document.getElementById('id_question2').value.toUpperCase().replace(/\\/g, "");
  /*❓: Are sure there's a <div id="div">? */
  let div1 = document.getElementById('div');
  /*❌: '...' or '..." NOT '..." */
  let div2 = document.getElementById('div2');
  /*❓: var hoists to be global use let or const. In this case let 
        is the best choice
  */
  var correctAnswers = 0;

  fetch(`/check/${id}`)
    .then(response => response.json())
    .then(quiz => {
      /*❓: Is rightM declared elsewhere? If not,
             use let or const
      */
      rightM = "You got this correct. Great job!";

      let answ1 = quiz.answer1.toUpperCase().replace(/\s/g, "");
      if (answ1 === response1) {
        div1.innerHTML = rightM;
        div1.classList.add("correct");
        correctAnswers++;
      } else {
        div1.innerHTML = `The correct answer is ${quiz.answer1}. Nice try!`;
        div1.classList.add("incorrect");
      }

      let answ2 = quiz.answer1.toUpperCase().replace(/\s/g, "");
      if (answ2 === response2) {
        div2.innerHTML = rightM;
        div2.classList.add("correct");
        correctAnswers++;
      } else {
        div2.innerHTML = `The correct answer is ${quiz.answer2}. Nice try!`;
        div2.classList.add("incorrect");
      }
      /*🚩: DRY = Don't Reapeat Yourself. Iterate through quiz.answer1 with
             a loop or an array method.
      */
      //this repeats 8 more times

      console.log(correctAnswers);
      let score = document.getElementById("score");
      /*❌: ` missing */
      /*❌: $' '{ space between $ and { breaks interpolation */
      score.innerHTML = `
      Your score is ${correctAnswers}.Great job!:)`;
      score.classList.add("score_style");
      /*❓: is newPoint declare elsewhere? If not use let or const */
      newPoints = correctAnswers * 10;

      let currentUser = parseInt(document.getElementById("user_id").value);
      let currentPoints = parseInt(document.getElementById("user_points").value);
      let numOfPoints = currentPoints + newPoints;
      /*❌: ` missing*/
      fetch(`/points/${currentUser}`, {
        method: "PUT",
        body: JSON.stringify({
          points: numOfPoints
        })
      });
    });
}

Update 1

As requested examples B and C include JavaScript that'll enable a disabled <button> when all <input>have text.

If you have a <form> wrapped around everything (which is very simple to do if you don't), add required to all of the <input> -- that'll prevent the <form> from being submitted should there be any blank <input>s (see Example A).

Example A - Has no JavaScript or CSS -- just HTML. The <button> isn't disabled, but the <form> will not allow itself to be submitted if any <input> is blank.

Example B - Has a <form> and uses HTMLFormElement and HTMLFormControlsCollection interfaces which facilitates the use of form controls.

Example C - Is a less elegant solution involving standard DOM manipulation.

Note that in Example B the event handler is bound to the <form> and that it is shared by each <input>. Should any form control be added to the <form> later on, the event handling will apply to it as well. In Example C each <input> has the input bound to them individually. Should any form control be added later on they'll need to have their own event handler/listener attached after they have been created.

Examples B and C have commented details

Example A

<form>
  <input required value='XXXXXXXXXXX'><br>
  <input required value='XXXXXXXXXXX'><br>
  <input required placeholder='Enter text here'><br>
  <button>Submit</button>
</form>

Example B

// Reference the <form>
const F = document.forms[0];
// Reference all form controls
const fc = F.elements;
// Collect all name='required' into a HTMLCollection, convert it into an array
const required = [...fc.required];
// Reference the <button>
const done = fc.done;
/**
 * Bind input event to <form>...
 * ...enable the <button> if .every() <input> has a value
 */
F.oninput = e =>
  done.disabled = !required.every(input => input.value.length > 0);
<form>
  <input name='required' value='XXXXXXXXXXX'><br>
  <input name='required' value='XXXXXXXXXXX'><br>
  <input name='required' placeholder='Enter text here'><br>
  <button id='done' disabled>Done</button>
</form>

Example C

// Collect all .required into a NodeList, convert it into an array
const required = [...document.querySelectorAll('.required')];
// Reference the <button>
const done = document.getElementById('done');
/**
 * Bind the input event to each <input>...
 * ...<button> is enabled if .every() <input> has a value
 */
required.forEach(input => input.oninput = e =>
  done.disabled = !required.every(input => input.value.length > 0));
<form>
  <input class='required' value='XXXXXXXXXXX'><br>
  <input class='required' value='XXXXXXXXXXX'><br>
  <input class='required' placeholder='Enter text here'><br>
  <button id='done' disabled>Done</button>
</form>

Sign up to request clarification or add additional context in comments.

14 Comments

that does not work correctly because I have made it so that once the button is clicked, the answers to the questions appear. I tried changing it to a form and adding the required attribute, but once the button was clicked, it still displayed the answers. Do you know how to check if the inputs are filled so that I can enable/disable the button accordingly?
Ok, updated with 2 extra examples.
I am trying to implement example C. I have placed at the beginning of the same function that checks the answers, which runs when the button is clicked, but nothing is happening when you press the button even if the input fields are filled.
Exactly where on the page do you put the JS or do you use an external file? Also, those are arrow functions so place them above any code that might have dependency on them. Anything the arrow function has a dependency on should be above it. Or convert them into named functions.
is there any way to do this without a form because the form tags are messing with the part of my code that displays whether the answers are right or wrong and, when I try to not use a form tag, the quiz doesn't submit. Is there any way to select all the inputs and check whether they are blank like with an if, and else make the button enabled. (I am using an external file for my JS.)
|

Your Answer

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.