javascripthtmlmultiple-choice

Javascripts multiple choice onclick modify all questions


I build this multiple choice questions but not in quiz format. I have in the page an sequence of divs with questions and each question have their own choices and check button, so they are independent and free for the users to respond one, all or none. I made the content (questions and answers) wrote directly on HTML file because I have others working with me and they have only contact with the HTML files to implement some classes.

My problem is that I made one question and it's working, but when a duplicated the div with another question the interaction affects all the divs. For exemple:

So I want to make each div with question be independent, in a way that we can create as many questions as we want.

I created this https://jsfiddle.net/1yLwrcek/2/

let mcqCard = document.querySelectorAll('.mcq-card');
let answerOption = document.querySelectorAll('.mcq__answers li');
let submitButton = document.querySelector('.mcq__submit button');
let submitFeedback = document.querySelector('.mcq__submit--feedback');
let score = 0;

(function () {
    // Select option, clear the others and enable submit
    answerOption.forEach(option => {
        option.addEventListener('click', function () {
            console.log(submitButton.getAttribute('type'));

            answerSelect(option);
        });
    });

    //Submit button to check only selected class option.
    submitButton.addEventListener('click', function () {
        if (submitButton.getAttribute('type') === 'submit' && submitButton.getAttribute('aria-disabled') === 'false') {
            butttonCheck();
        } else {
            buttonReset();
        }
    });
})();

function answerSelect(e) {
    if (submitButton.getAttribute('type') === 'submit') {
        for (let i = 0; i < answerOption.length; i++) {
            const element = answerOption[i];
            element.classList.remove('mcq__answers--selected');
        }
        e.classList.add('mcq__answers--selected');
        submitButton.setAttribute('aria-disabled', 'false');
    }
}

function incorrectAnswer(event) {
    event.classList.remove('mcq__answers--selected');
    event.classList.add('mcq__answers--incorrect');

    submitFeedback.innerHTML = `<span class="material-symbols-rounded">cancel</span>Resposta errada! <br class="d-lg-none" />Tente novamente.`;
    submitFeedback.classList.remove('d-none', 'mcq__submit__feedback--correct');
    submitFeedback.classList.add('mcq__submit__feedback--incorrect');
}

function correctAnswer(event) {
    event.classList.remove('mcq__answers--selected');
    event.classList.add('mcq__answers--correct');

    submitFeedback.innerHTML = `<span class="material-symbols-rounded">check_circle</span>Resposta correta! <br class="d-lg-none" />Você acertou em ${score} tentativa(s).`;
    submitFeedback.classList.remove('d-none', 'mcq__submit__feedback--incorrect');
    submitFeedback.classList.add('mcq__submit__feedback--correct');
}

function blockAnswerOption() {
    for (let i = 0; i < answerOption.length; i++) {
        const element = answerOption[i];

        element.classList.add('mcq__answers--blocked');
    }
}

function butttonCheck() {
    if (submitButton.getAttribute('type') === 'submit') {
        score++;

        for (let i = 0; i < answerOption.length; i++) {
            const element = answerOption[i];

            if (element.classList.contains('mcq__answers--selected')) {
                if (!element.hasAttribute('correct')) {
                    incorrectAnswer(element);
                    blockAnswerOption();
                } else {
                    correctAnswer(element);
                    blockAnswerOption();
                }
            }
        }
        submitButton.setAttribute('type', 'reset');
        submitButton.innerHTML = 'Reset';
    }
}

function buttonReset() {
    if (submitButton.getAttribute('type') === 'reset') {
        for (let i = 0; i < answerOption.length; i++) {
            const element = answerOption[i];

            element.classList.remove('mcq__answers--correct', 'mcq__answers--incorrect', 'mcq__answers--blocked', 'mcq__answers--selected');
            submitButton.setAttribute('type', 'submit');
            submitButton.innerHTML = 'Check';
            submitButton.setAttribute('aria-disabled', 'true');
        }

        if (submitFeedback.classList.contains('mcq__submit__feedback--correct')) {
            score = 0;
        }
        submitFeedback.classList.remove('mcq__submit__feedback--correct', 'mcq__submit__feedback--incorrect');
        submitFeedback.classList.add('d-none');
    }
}
:root {
    /* Colors */
    --primary-color: #d27f7d;
    --primary-color-light: #ee9b9a;
    --primary-color-dark: #bb6564;

    --secondary-color: #8a6580;
    --secondary-color-extra-light: #fae9f5;
    --secondary-color-light: #c28cb4;
    --secondary-color-dark: #5a3751;

    --text-color: #1e1e1e;
    --text-color-light: #535658;

    --color-dark: #1e1e1e;
  --color-light: #eef2f6;
    --color-light-hover: #e6e6e625;
}



.mcq-card {
    padding: 0px 30px;
}
.mcq-card .mcq__question {
    padding: 30px 0;
    border-bottom: 1px solid var(--secondary-color-light);
    font-family: 'DM Sans Bold', sans-serif;
    font-size: 1.25rem;
}

/* Answers List */
.mcq-card .mcq__answers {
    padding: 30px 0;
}
.mcq-card .mcq__answers ul {
    list-style-type: none;
    margin: 0;
}
.mcq-card .mcq__answers ul li {
    padding: 10px 20px;
    margin-bottom: 20px;
    border: 2px solid var(--primary-color-light);
    border-radius: 8px;
    cursor: pointer;
    font-size: 1rem;
    transition: 0.1s;
}
.mcq-card .mcq__answers ul li:last-child {
    margin-bottom: 0;
}
.mcq-card .mcq__answers ul li:not(.mcq__answers--blocked, .mcq__answers--selected, .mcq__answers--correct, .mcq__answers--incorrect):hover {
    border-color: var(--primary-color-dark);
    /* background-color: var(--color-light-hover); */
}
.mcq-card .mcq__answers ul li.mcq__answers--selected {
    background-color: var(--secondary-color-extra-light);
    border-color: var(--secondary-color-light);
    color: var(--secondary-color-dark);
}
.mcq-card .mcq__answers ul li.mcq__answers--correct {
    background-color: #c0ffce;
    border-color: #28a745;
    color: #014811;
    cursor: not-allowed;
}
.mcq-card .mcq__answers ul li.mcq__answers--incorrect {
    background-color: #ffc5cb;
    border-color: #dc3545;
    color: #81000c;
    cursor: not-allowed;
}
.mcq-card .mcq__answers ul li.mcq__answers--blocked:not(.mcq__answers--correct, .mcq__answers--incorrect) {
    cursor: not-allowed;
    border-color: var(--color-light);
    color: var(--text-color-light);
}

/* Submit Button */
.mcq-card .mcq__submit {
    display: flex;
    flex-direction: row;
    justify-content: start;
    align-items: center;
    padding: 30px 0;
    border-top: 1px solid var(--secondary-color-light);
}
.mcq-card .mcq__submit button[aria-disabled='true'] {
    background-color: #909599;
    border-color: #909599;
    cursor: not-allowed;
}

/* Feedback mensage */
.mcq-card .mcq__submit .mcq__submit--feedback {
    font-family: 'DM Sans Bold', sans-serif;
    margin-left: 20px;
    line-height: 1.2;
}
.mcq-card .mcq__submit .mcq__submit--feedback .material-symbols-rounded {
    font-weight: 700;
    margin-right: 10px;
}
.mcq-card .mcq__submit .mcq__submit--feedback.mcq__submit__feedback--correct {
    display: block !important;
    color: #28a745;
}
.mcq-card .mcq__submit .mcq__submit--feedback.mcq__submit__feedback--incorrect {
    display: block !important;
    color: #dc3545;
}
<div class="mcq-card card shadow round border-0">
  <div class="mcq__question">1. Question</div>
  <div class="mcq__answers">
    <ul>
      <li tabindex="0">Option 1</li>
      <li tabindex="0">Option 2</li>
      <li tabindex="0" correct>Option 3</li>
    </ul>
  </div>
  <div class="mcq__submit">
    <button class="button-primary" aria-disabled="true" type="submit">Check</button>
    <span class="d-none mcq__submit--feedback"></span>
  </div>
</div>

<div class="mcq-card card shadow round border-0">
  <div class="mcq__question">2. Question</div>
  <div class="mcq__answers">
    <ul>
      <li tabindex="0">Option 1</li>
      <li tabindex="0">Option 2</li>
      <li tabindex="0" correct>Option 3</li>
    </ul>
  </div>
  <div class="mcq__submit">
    <button class="button-primary" aria-disabled="true" type="submit">Check</button>
    <span class="d-none mcq__submit--feedback"></span>
  </div>
</div>

Thanks


Solution

  • Because each question has exact same structure, you'll need either assign an unique ID for each or go by its index. But most simple solution is to query each element of each question separately:

    let mcqCard = document.querySelectorAll('.mcq-card');
    let score = 0;
    
    (function () {
      mcqCard.forEach(mcq =>
      {
        let answerOption = mcq.querySelectorAll('.mcq__answers li');
        let submitButton = mcq.querySelector('.mcq__submit button');
        let submitFeedback = mcq.querySelector('.mcq__submit--feedback');
        // Select option, clear the others and enable submit
        answerOption.forEach(option => {
            option.addEventListener('click', function () {
                console.log(submitButton.getAttribute('type'));
    
                answerSelect(option, submitButton, answerOption);
            });
        });
    
        //Submit button to check only selected class option.
        submitButton.addEventListener('click', function () {
            if (submitButton.getAttribute('type') === 'submit' && submitButton.getAttribute('aria-disabled') === 'false')         {
                butttonCheck();
            } else {
                buttonReset();
            }
        });
        
        function answerSelect(e, submitButton) {
            if (submitButton.getAttribute('type') === 'submit') {
                for (let i = 0; i < answerOption.length; i++) {
                    const element = answerOption[i];
                    element.classList.remove('mcq__answers--selected');
                }
                e.classList.add('mcq__answers--selected');
                submitButton.setAttribute('aria-disabled', 'false');
            }
        }
    
        function incorrectAnswer(event) {
            event.classList.remove('mcq__answers--selected');
            event.classList.add('mcq__answers--incorrect');
    
            submitFeedback.innerHTML = `<span class="material-symbols-rounded">cancel</span>Resposta errada! <br class="d-lg-none" />Tente novamente.`;
            submitFeedback.classList.remove('d-none', 'mcq__submit__feedback--correct');
            submitFeedback.classList.add('mcq__submit__feedback--incorrect');
        }
    
        function correctAnswer(event) {
            event.classList.remove('mcq__answers--selected');
            event.classList.add('mcq__answers--correct');
    
            submitFeedback.innerHTML = `<span class="material-symbols-rounded">check_circle</span>Resposta correta! <br class="d-lg-none" />Você acertou em ${score} tentativa(s).`;
            submitFeedback.classList.remove('d-none', 'mcq__submit__feedback--incorrect');
            submitFeedback.classList.add('mcq__submit__feedback--correct');
        }
    
        function blockAnswerOption() {
            for (let i = 0; i < answerOption.length; i++) {
                const element = answerOption[i];
    
                element.classList.add('mcq__answers--blocked');
            }
        }
    
        function butttonCheck() {
            if (submitButton.getAttribute('type') === 'submit') {
                score++;
    
                for (let i = 0; i < answerOption.length; i++) {
                    const element = answerOption[i];
    
                    if (element.classList.contains('mcq__answers--selected')) {
                        if (!element.hasAttribute('correct')) {
                            incorrectAnswer(element);
                            blockAnswerOption();
                        } else {
                            correctAnswer(element);
                            blockAnswerOption();
                        }
                    }
                }
                submitButton.setAttribute('type', 'reset');
                submitButton.innerHTML = 'Reset';
            }
        }
    
        function buttonReset() {
            if (submitButton.getAttribute('type') === 'reset') {
                for (let i = 0; i < answerOption.length; i++) {
                    const element = answerOption[i];
    
                    element.classList.remove('mcq__answers--correct', 'mcq__answers--incorrect', 'mcq__answers--blocked', 'mcq__answers--selected');
                    submitButton.setAttribute('type', 'submit');
                    submitButton.innerHTML = 'Check';
                    submitButton.setAttribute('aria-disabled', 'true');
                }
    
                if (submitFeedback.classList.contains('mcq__submit__feedback--correct')) {
                    score = 0;
                }
                submitFeedback.classList.remove('mcq__submit__feedback--correct', 'mcq__submit__feedback--incorrect');
                submitFeedback.classList.add('d-none');
            }
        }
    });
    })();
    :root {
        /* Colors */
        --primary-color: #d27f7d;
        --primary-color-light: #ee9b9a;
        --primary-color-dark: #bb6564;
    
        --secondary-color: #8a6580;
        --secondary-color-extra-light: #fae9f5;
        --secondary-color-light: #c28cb4;
        --secondary-color-dark: #5a3751;
    
        --text-color: #1e1e1e;
        --text-color-light: #535658;
    
        --color-dark: #1e1e1e;
      --color-light: #eef2f6;
        --color-light-hover: #e6e6e625;
    }
    
    
    
    .mcq-card {
        padding: 0px 30px;
    }
    .mcq-card .mcq__question {
        padding: 30px 0;
        border-bottom: 1px solid var(--secondary-color-light);
        font-family: 'DM Sans Bold', sans-serif;
        font-size: 1.25rem;
    }
    
    /* Answers List */
    .mcq-card .mcq__answers {
        padding: 30px 0;
    }
    .mcq-card .mcq__answers ul {
        list-style-type: none;
        margin: 0;
    }
    .mcq-card .mcq__answers ul li {
        padding: 10px 20px;
        margin-bottom: 20px;
        border: 2px solid var(--primary-color-light);
        border-radius: 8px;
        cursor: pointer;
        font-size: 1rem;
        transition: 0.1s;
    }
    .mcq-card .mcq__answers ul li:last-child {
        margin-bottom: 0;
    }
    .mcq-card .mcq__answers ul li:not(.mcq__answers--blocked, .mcq__answers--selected, .mcq__answers--correct, .mcq__answers--incorrect):hover {
        border-color: var(--primary-color-dark);
        /* background-color: var(--color-light-hover); */
    }
    .mcq-card .mcq__answers ul li.mcq__answers--selected {
        background-color: var(--secondary-color-extra-light);
        border-color: var(--secondary-color-light);
        color: var(--secondary-color-dark);
    }
    .mcq-card .mcq__answers ul li.mcq__answers--correct {
        background-color: #c0ffce;
        border-color: #28a745;
        color: #014811;
        cursor: not-allowed;
    }
    .mcq-card .mcq__answers ul li.mcq__answers--incorrect {
        background-color: #ffc5cb;
        border-color: #dc3545;
        color: #81000c;
        cursor: not-allowed;
    }
    .mcq-card .mcq__answers ul li.mcq__answers--blocked:not(.mcq__answers--correct, .mcq__answers--incorrect) {
        cursor: not-allowed;
        border-color: var(--color-light);
        color: var(--text-color-light);
    }
    
    /* Submit Button */
    .mcq-card .mcq__submit {
        display: flex;
        flex-direction: row;
        justify-content: start;
        align-items: center;
        padding: 30px 0;
        border-top: 1px solid var(--secondary-color-light);
    }
    .mcq-card .mcq__submit button[aria-disabled='true'] {
        background-color: #909599;
        border-color: #909599;
        cursor: not-allowed;
    }
    
    /* Feedback mensage */
    .mcq-card .mcq__submit .mcq__submit--feedback {
        font-family: 'DM Sans Bold', sans-serif;
        margin-left: 20px;
        line-height: 1.2;
    }
    .mcq-card .mcq__submit .mcq__submit--feedback .material-symbols-rounded {
        font-weight: 700;
        margin-right: 10px;
    }
    .mcq-card .mcq__submit .mcq__submit--feedback.mcq__submit__feedback--correct {
        display: block !important;
        color: #28a745;
    }
    .mcq-card .mcq__submit .mcq__submit--feedback.mcq__submit__feedback--incorrect {
        display: block !important;
        color: #dc3545;
    }
    <div class="mcq-card card shadow round border-0">
      <div class="mcq__question">1. Question</div>
      <div class="mcq__answers">
        <ul>
          <li tabindex="0">Option 1</li>
          <li tabindex="0">Option 2</li>
          <li tabindex="0" correct>Option 3</li>
        </ul>
      </div>
      <div class="mcq__submit">
        <button class="button-primary" aria-disabled="true" type="submit">Check</button>
        <span class="d-none mcq__submit--feedback"></span>
      </div>
    </div>
    
    <div class="mcq-card card shadow round border-0">
      <div class="mcq__question">2. Question</div>
      <div class="mcq__answers">
        <ul>
          <li tabindex="0">Option 1</li>
          <li tabindex="0">Option 2</li>
          <li tabindex="0" correct>Option 3</li>
        </ul>
      </div>
      <div class="mcq__submit">
        <button class="button-primary" aria-disabled="true" type="submit">Check</button>
        <span class="d-none mcq__submit--feedback"></span>
      </div>
    </div>