Getting Loopy – Nested Javascript Loops

Complex loops with Javascript can get tricky. Double-nested loops, dynamic field names, and all kinds of other things can leave a programmers head spinning. Let’s get Loopy and tackle this in a nice programatical manner.

Recently presented with a form similar to a questionnaire, there were a bunch of questions, each with the possibility of multiple answer options and a comment box. To make matters worse, I needed to check if there were comments entered when a certain option was selected. Rather than go through one by one and create a huge function, I tapped into the power of loops, and the power of dynamic form element naming.

Let’s say our form is a questionnaire with radio buttons for options and a comment box. The form would look something like this:


<div>
  <form id="frmdefault" onsubmit="validateForm();" method="post" action="results.php">
    <table>  
      <tr>
        <td>Q1</td>
        <td><strong>How good are you at javascript?</strong></td>
        <td><input type="radio" id="q1" name="q1" value="Great" />Great!</td>
        <td><input type="radio" id="q1" name="q1" value="Average" />Average</td>
        <td><input type="radio" id="q1" name="q1" value="Bad" />Bad</td>
        <td><input type="radio" id="q1" name="q1" value="NA" />N/A</td>  
        <td><textarea id="q1_comments" name="q1_comments" rows="2" cols="5"></textarea></td>
      </tr>
      <tr>
        <td>Q2</td>
        <td><strong>How do you think this tutorial rates?</strong></td>
        <td><input type="radio" id="q2" name="q2" value="Great" />Great!</td>
        <td><input type="radio" id="q2" name="q2" value="Average" />Average</td>
        <td><input type="radio" id="q2" name="q2" value="Bad" />Bad</td>
        <td><input type="radio" id="q2" name="q2" value="NA" />N/A</td>  
        <td><textarea id="q2_comments" name="q2_comments" rows="2" cols="5"></textarea></td>
      </tr>
      <tr>
        <td colspan="7"><input type="submit" value="Validate Form" /></td>
      </tr>
    </table>
  </form>
</div>

This makes our nice little form. Of course, you can make it into nice table-less layout and all that, but that is beyond the scope of this article, so I used a table.

Let’s say that we want to:

  1. Make sure a radio option is selected for each question
  2. require a comment to be entered in the textarea if “Bad” is selected

In order to do this, we need to first loop through our radio buttons to see if one is selected. If “bad” is selected, prompt for comments to be entered. Finally, we need to loop and repeat the above for every question.

In less than 30 lines of (well-formatted) code, we can set up a double-looping function that does all of this, will work for an infinite amount of questions or possible answers (except a single answer- but, you shouldn’t be using radio buttons for a single element choice anyway). I will explain the code below the function:


<script type="text/javascript">

function validateForm() {
  var theform = document.getElementById("frmdefault");

  for (i=1; i<3; i++)
  {
    for (j=0; j<theform .elements["q"+i].length; j++)
    {
      if (theform.elements["q"+i][j].checked)
      {
        if (theform.elements["q"+i][j].value == "Bad")
        {
          if(theform.elements["q"+i+"_comments"].value == "")
          {
            alert("Comments required for Q"+i+" when Bad is selected");
            theform.elements["q"+i+"_comments"].focus();
            return false;
          }
        }
      }
      else
      {
        alert("Please select an option");
        return false;
      }
    }
  }
}
</script>

It looks very complex and tricky, but as we go through it you will see it makes a lot of sense. The outer loop is set for the number of questions we have. In this case, we have 2. You could port this a step further an make this number count dynamic as well. (In most cases though, I feel as if that’s an unnecessary step as most polls or scripts like this won’t change once made. If you are running some kind of dynamic form generator, then yes, another step will need to be added to find how many questions there are. Basically, you’d have to add another loop around all of the above that counts how many questions there are.)

Notice, we start with i=1 instead of the common i=0. This is because our questionnaire starts with question 1, not question 0. It makes things easier to address in the inner functions. Because of this, we also must up our incremented variable to i<3 instead of i<2, because of the increased initialized variable. Another option would be to use i< =2, thus allowing for it to be equal to the max index.

The outer loop, i, will call the inner loop j, i times. Inside the inner loop, we need to dynamically address how many radio buttons there are. The length function figures this out for us and begins our data check to ensure at least one element is checked per our requirements. Note that we are using ["q"+i]. This evaluates to our question number based off the outer loop. If the element array does not have one checked, it will return false and prompt the user to select one. If there is an element checked, it will then look and see if that checked value = “Bad”. If it is, it then checks to see if there is anything in the textarea field for comments. If not, we return home free and we return to the outer loop for testing the question count to see if we need to do this all over again for the next question, if one exists. When all is passed, the form will submit to the target in the action attribute of the form tag, in our example, results.php.

Of course, this all depends on Javascript being enabled, and in a browser than supports the getElementById() functionality. Thus, it is important to also use server-side scripting to double check the submitted results. The Javascript just adds a friendly alert so that the whole page doesn’t need to be submitted every time an error occurs.

Have a better idea? I’m sure this code can be improved upon, and thus I’m curious to hear if anyone else has a similar function set up for this type of form checking. I appreciate your comments, as always.

This entry was posted in Programming and tagged , . Bookmark the permalink.

One Response to Getting Loopy – Nested Javascript Loops

  1. I recently had an email request for a similar function set, but without the extra bloat of checking a textarea. Rather it was just a multiple question, multiple choice radio button form.

    The method is similar. In this example, assume there were 5 questions in form id=”frm1″, each with more than 1 radio option as a possible response.


    function validate() {
      var theform = document.getElementById("frm1");

      //check radio boxes
      var setflag;
      setflag = false;
      
      for (i=1; i<6; i++)      // N questions + 1
      {
        for (j=0; j<theform.elements["q"+i].length; j++)
        {
          if (theform.elements["q"+i][j].checked)
          {
            setflag = true;
          }
        }

        if (setflag == false)
        {
          alert("Please Answer Question #" + i);
          theform.elements["q"+i][0].focus();
          return false;
        }

        setflag = false;
      }
       }

    It’s as easy as that :)

    Enjoy.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>