2

I'm trying my hand at Javascript and interacting with the DOM for the first time by making a simple quiz game. All of my elements are generated dynamically by JS except a few divs.

so here is my problem.

I have

Question 1.
(A)
(B)
(C)
(D)

I want to be able to click on any of the answers and have the values returned. To do that, I wrote the function

function checkCorrectness(element){
    element.onclick = function(){       
        nodes = element.childNodes
        for(i = 0; i<nodes.length; i++){
            nodes[i].onclick = function(){console.log(nodes)};
        }
    }
 }
//Note answers selectsthe div containing the 4 <p> elements A,B,C,D
checkCorrectness(answers)

Which returns me, as expected, an array of the four

elements containing my answers. So, I thought the logical next step would be to select the particular node onClick by changing it by console.log-ing nodes[i] instead of nodes. I would expect this to return me the element which I clicked on, so I could compare its inner HTML to the correct answer, therefore seeing if it was the right answer.

function checkCorrectness(element){
    element.onclick = function(){       
        nodes = element.childNodes
        for(i = 0; i<nodes.length; i++){
            nodes[i].onclick = function(){console.log(nodes[i])};
        }
    }
 }

 checkCorrectness(answers)

However, it just returns undefined. Any help would be much appreciated!

jasnonaz
  • 57
  • 5

2 Answers2

2

Ah, you've discovered JavaScript closures (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures). This is a very common mistake for those new to JS, so don't feel bad. When you log nodes[i], you're actually accessing nodes at the index for the most recent value of "i" at the time the function executes. Which, in this case, is nodes.length, which is undefined... sorry if that doesn't make sense, but check out the linked article.

You really want something like this:

var logNode = function(val) {
    return function() { console.log(nodes[val]) };
};

for(i = 0; i<nodes.length; i++){
    nodes[i].onclick = logNode(i);
}
joeltine
  • 1,610
  • 17
  • 23
  • ahhh, that's was going on. Weird. I shall reavalute and attempt to fix it! Thank you for your help! – jasnonaz Aug 09 '14 at 04:54
  • 1
    No problem. Please mark the answer as "accepted" if this solves your issue, so other people can benefit :). – joeltine Aug 09 '14 at 04:58
  • Will do! I actually had to stop working for the evening unfortunately, I'll see if I can implement this first thing tomorrow morning. – jasnonaz Aug 09 '14 at 05:06
  • Whooo that did it, thank you! Closures are weird. definitely gonna have to get used to them. – jasnonaz Aug 09 '14 at 15:20
1

The whole logic of your quiz may be written in a couple of lines

// JavaScript
window.onload = function(){
  // This is a simple structure to hold your question_id and the correct answer
  // var data = {'10':'B', '11':'D', '12':'A', '13':'A'}; ...
  // for this exampple we'll have only one
  var data = {'10':'B'};  
  var li = document.getElementsByTagName('UL')[0].children;
  for(i = 0; i < li.length; i++){
    li[i].onclick = function(){
      if(data[this.parentNode.id] == this.innerHTML){
        alert(this.innerHTML + " -> Correct"); 
      }else{
        alert('Nope!');
      }
    };
  }
};

// HTML
// Let's say every question has an `id` 
// I'd use a list for this case but you may use any other markup 
<ul id="10">
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
</ul>

Working jsBin

hex494D49
  • 9,109
  • 3
  • 38
  • 47