A table with interactive responses

Hello!

I’m trying (unsuccessfully :rolleyes:) to modify some code I was given. The goal is to print particular messages when a user enters correct or incorrect information into a table (the table is demonstrating the FOIL method from algebra). Right now, nothing happens! In theory, if an answer is correct, the word “Correct” should appear in the appropriate <td></td> near the input box; if it’s incorrect, 3 different messages are shown. I’d appreciate it if someone could please show me the error of my ways.

Thank you,

Eric

<table id="table1" class="center_table" width="120" border="0" cellspacing="0" cellpadding="5" summary="Showing the Foil Method">
    
    <tr>
      <td>&nbsp;</td>
      <td class="underline_row" colspan="2" align="center"><span lang="latex">2x+3</span></td>
      </tr>
    <tr>
      <td class="underline_right"><span lang="latex">x</span></td>
      <td rowspan="2" align="center"><span lang="latex">2x^2</span></td>
      <td class="underline_right" rowspan="2"><input name="" type="text" size="2" maxlength="2" /></td><td name="response" rowspan="2"></td>
    </tr>
    <tr>
      <td class="underline_right"><span  lang="latex">+</span></td>
    </tr>
    <tr>
      <td class="underline_right"><span lang="latex">2</span></td>
      <td class="underline_row"><input name="" type="text" size="2" maxlength="2" /></td>
      <td class="underline_right_corner"><input name="" type="text" size="2" maxlength="2" /></td>
      <tr><td> </td><td name="response"></td><td name="response"></td>
    </tr>
  </table>


            var answers1 = new Array("3x","4x","6");
			
			wrong_answers1[0] = "Did you square first?";
			wrong_answers1[1] = "Are you sure about that?";
	        wrong_answers1[2] = "Not quite!";

            function checkAnswer(obj,answers,wrong_answers,response){
			    response.innerHTML = (obj.value == answers[obj.qNum]) ? 'Correct!' : wrong_answers1[obj.qNum];
            }
           function check_text_questions(text_group,answers,wrong_answers){
                var oAnsInputs = document.getElementById(text_group).getElementsByTagName("input");
				
				var oAnsOutputs = document.getElementsByName("response")
				
                for(i=0; i < oAnsInputs.length; i++){
                    oAnsInputs[i].onchange=function(){checkAnswer(this,answers,wrong_answers,oAnsOutputs[i]);}
                    oAnsInputs[i].qNum = i;
					
				}
          }
		  
  check_text_questions('table1',answers1,wrong_answers1);

Here’s one of the problems.

The wrong_answers1 variable does not exist, so the script halts complaining about that.

You can either add an assignment for the array:


wrong_answers1 = [];
wrong_answers1[0] = "Did you square first?";
wrong_answers1[1] = "Are you sure about that?";
wrong_answers1[2] = "Not quite!";

Or, you can use more expressive code to create the array:


wrong_answers1 = [
    'Did you square first?',
    'Are you sure about that?',
    'Not quite!'
];

Here’s the next problem.

When the for loop is used to assign the function, the variable i has no effect on the code itself. When the function is triggered at the time of the onchange event, the i variable will be what it was at the end of the for loop, which is 3.

Let’s pull that function out to a different location, so that the problem can be more easily seen.


function onchangeEventHandler() {
    checkAnswer(this, answers, wrong_answers, oAnsOutputs[i]);
}
for (i = 0; i < oAnsInputs.length; i++) {
    oAnsInputs[i].onchange = onchangeEventHandler;
    ...
}

Now it’s easy to tell that the onchange event is being assigned only a reference to the function. The code within the function won’t be executed until long after the for loop has finished.

Because of this, there’s a good rule of thumb that you should not create a function from within a loop.

One way to deal with that is to pass oAnsOutputs[i] to a function, which can then accept that value so it can be used by the event handler function.


function assignCheckAnswerEvent(oAnsOutput) {
    return function () {
        checkAnswer(this, answers, wrong_answers, oAnsOutput);
    }
}
for (i = 0; i < oAnsInputs.length; i++) {
    oAnsInputs[i].onchange = assignCheckAnswerEvent(oAnsOutputs[i]);
    ...
}

And yes, you can condense that down to:


for (i = 0; i < oAnsInputs.length; i++) {
    oAnsInputs[i].onchange = function (oAnsOutput) {
        return function () {
            checkAnswer(this, answers, wrong_answers, oAnsOutput);
        }
    }(oAnsOutputs[i]);
    ...
}

But it might be more difficult to understand that than the code just above it.

Another great response…looking forward to learning how to use more of the javascript tools from this forum. :cool:

-Eric