Linking data value in HTML with array value in JS

I’m building a site that contains several quizzes. To avoid redundant code, each quiz will have a javascript array to hold the answers - an answer key. I’m wanting to do all of this client-side with JS/JQuery. I need to link each quiz question with it’s answer in it’s corresponding answer key. Here’s a snippet of 2 questions from one of the quizzes. (The .check-answer button is not a submit button because I don’t want to submit anything to the server.)


<li class="group">
    <div class="question group">
        <p>What note is this?</p>
        <img src="../img/Quiz/notesOnTrebleQuiz/C5.gif" alt="3rd space from bottom" />
    </div><!-- end .question -->
    <div class="choices">
        <form data-question-id="1">
            <label>
                <input name="quizAnswer" id="notesOnTrebleQuiz_Q1A1" type="radio" value="A" />A
            </label>
            <label>
                <input name="quizAnswer" id="notesOnTrebleQuiz_Q1A2" type="radio" value="B" />B
            </label>
            <label>
                <input name="quizAnswer" id="notesOnTrebleQuiz_Q1A3" type="radio" value="C" />C
            </label>
            <label>
                <input name="quizAnswer" id="notesOnTrebleQuiz_Q1A4" type="radio" value="D" />D
            </label>
            <label>
                <input name="quizAnswer" id="notesOnTrebleQuiz_Q1A5" type="radio" value="E" />E
            </label>
            <label>
                <input name="quizAnswer" id="notesOnTrebleQuiz_Q1A6" type="radio" value="F" />F
            </label>
            <label>
                <input name="quizAnswer" id="notesOnTrebleQuiz_Q1A7" type="radio" value="G" />G
            </label>
            <a class="check-answer">check answer</a>
        </form>
    </div><!-- end .choices -->
    <div class="answer">
        <p class="correct">Correct!</p>
        <p class="incorrect">Incorrect.</p>
    </div><!-- end .answer -->
</li>
<li class="group">
    <div class="question group">
        <p>What note is this?</p>
        <img src="../img/Quiz/notesOnTrebleQuiz/F4.gif" alt="1st space on bottom" />
    </div><!-- end .question -->
    <div class="choices">
        <form data-question-id="2">
        <label>
            <input name="quizAnswer" type="radio" value="A" />A
        </label>
        <label>
            <input name="quizAnswer" type="radio" value="B" />B
        </label>
        <label>
            <input name="quizAnswer" type="radio" value="C" />C
        </label>
        <label>
            <input name="quizAnswer" type="radio" value="D" />D
        </label>
        <label>
            <input name="quizAnswer" type="radio" value="E" />E
        </label>
        <label>
            <input name="quizAnswer" type="radio" value="F" />F
        </label>
        <label>
            <input name="quizAnswer" type="radio" value="G" />G
        </label>
        <a class="check-answer">check answer</a>
        </form>
    </div><!-- end .choices -->
    <div class="answer">
        <p class="correct">Correct!</p>
        <p class="incorrect">Incorrect.</p>
    </div><!-- end .answer -->
</li>

And here’s my corresponding JS code:


var notesOnTrebleAnswerKey = {
                1: 'C',
                2: 'F',
                3: 'D',
                4: 'D',
                5: 'E',
                6: 'A',
                7: 'G',
                8: 'D',
                9: 'C',
                10: 'C',
                11: 'B',
                12: 'F',
                13: 'G',
                14: 'E',
                15: 'F',
                16: 'A',
                17: 'B',
                18: 'A',
                19: 'G',
                20: 'B',
                21: 'E',
                22: 'G'
}

//when check answer, provides response
$('.check-answer').click(function(){
var getResult = $(this).find('.answer');

var answers = $(this).parent('.choices');

var question = answers.data('question-id');//may need to separate .choices from data-question-id

var answer = answers.find('input:selected').val();

var correct = $('.answer').find('.correct');
var incorrect = $('.answer').find('.incorrect');

//Notes on Treble Quiz
if(notesOnTrebleAnswerKey[question] == answer){
                getResult.find('.correct').show();
                getResult.find('.incorrect').hide();
                /*
                correct.show();
                incorrect.hide();
                */
} else {
                getResult.find('.correct').hide();
                getResult.find('.incorrect').show();
                /*
                correct.hide();
                incorrect.show();
                */
}

I can’t figure out why this isn’t working. Can anyone help?

Unless this is a programming exercise you should not do this with javascript alone. You need to conceal the answers, and you cannot conceal your javascript code.

You can create an array using the names of the element.


&lt;input type="radio" name="answers[1]" value="1"&gt;
&lt;input type="radio" name="answers[1]" value="2"&gt;

That will produce a server side array that looks like this in PHP


array( '1' =&gt; '3'
  '2' =&gt; '1'
  '3' =&gt; ' 

That said, the main reason this isn’t working is ‘quizAnswers’ must have a different name for each question for the radio buttons to work correctly. Radio buttons only allow one to be selected for all the buttons that share the same name.

The errors I found all had to do with a misunderstanding of how jQuery searches the DOM, so let’s go through it one step at a time…

Which element do you start with?

Here’s your code:


$('.check-answer').click(function(){
    // ...
});

It’s waiting for an element with a class of “check-answer” to be clicked. That’s what “this” will refer to in the function. But your first line in the function is…


var getResult = $(this).find('.answer');

The find function searches child nodes, but “this” refers to an <a> element… It has no child nodes*, much less the .answer <div>.

*no child element nodes, anyway

Instead, a good starting point would be the <div> that has the “choices” class, so let’s start there:


var answers = $(this).parents('.choice');

Note that I used .parents, [b]not[/b] [url=http://api.jquery.com/parent/].parent. The former searches all of the ancestors, while the latter only looks at the immediate parent.

How do you get the question ID?

Again, here’s your code first:


var answers = $(this).parent('.choices');
var question = answers.data('question-id');

Even if we change the first line so that it uses .parents instead of .parent, there’s still a mistake: The data-question-id attribute isn’t on the .choices <div>, it’s on the <form>, which is a child of the <div>. So the quick fix is to just look for it:


var question = answers.find('form').data('question-id');

How do you get the answer that’s currently selected?

This is a simple change:


// you had this...
var answer = answers.find('input:selected').val();

// but "selected" is incorrect
// these are radio buttons, so we need "checked"
var answer = answers.find('input:checked').val();

Put it all together, and what do you get…

Here’s the kind-of-slimmed-down event listener after making these changes:


$('.check-answer').click(function() {
    var answers = $(this).parents('.choices');
    var getResult = answers.siblings('.answer'); // <-- used the .siblings method instead

    var question = answers.find('form').data('question-id');
    var answer = answers.find('input:checked').val();

    //Notes on Treble Quiz
    if (notesOnTrebleAnswerKey[question] == answer) {
        getResult.find('.correct').show();
        getResult.find('.incorrect').hide();
    } else {
        getResult.find('.correct').hide();
        getResult.find('.incorrect').show();
    }
});

You’re awesome.

Thanks.

Thanks for the response. I just started learning JS, so this is kind of a test to see if I could figure out how to do it with JS.

I agree that it would be better to have the answers concealed by using PHP, but I also want the users to have immediate feedback after answering each question. Plus, I’m not storing any of the data (yet), so I figured the easiest thing to do was to write it in JS.

Is there a way to do this with PHP that would still allow users immediate feedback - maybe store the array in PHP but load and access it somehow with JS? Obviously, I’m new at this. Your help is much appreciated.

Thank you so much for explaining this! Yes, I am new with JS. You helped me learn instead of just giving me an answer. Plus, it works! Thank you, sdleihssirhc!