Dynamic Forms

In this lesson of the JavaScript tutorial, you will learn...
  1. To create jump menus.
  2. To create interdependent select menus.
  3. To create a JavaScript TIMER
  4. To build a simple JavaScript testing tool.

Jump Menus

A jump menu is a select menu that contains a list of websites or pages to visit. There are two main types of jump menus. One jumps to the selected page as soon as the user makes a selection. The other jumps to a page only after the user has made a selection and clicked on a "Go" button. We'll look at the latter type first and then create the former type in an exercise.

Code Sample: DynamicForms/Demos/JumpMenus.html

<html>
<head>
<title>Jump Menus</title>
<script type="text/javascript">
function jumpMenu(select){
 var i = select.selectedIndex;
 var selection = select.options[i].value;
 var url;
 if (i === 0) {
  alert("Please select a state.");
 } else {
  url = "http://www.50states.com/" + selection + ".htm";
  location.href = url;
 }
}
</script>
</head>
<body>
<form>
 <select name="State">
  <option value="0">--SELECT A STATE--</option>
  <option value="alabama">Alabama</option>
  <option value="illinois">Illinois</option>
  <option value="massachu">Massachusetts</option>
  <option value="montana">Montana</option>
  <option value="ncarolin">North Carolina</option>
  <option value="wvirgini">West Virginia</option>
 </select>
 <input type="button" value="GO" 
   onclick="jumpMenu(this.form.State);">
</form>
</body>
</html>
Code Explanation

Viewed in a browser, the page looks like this:

The options[] Array

Select menus contain an array of options. Like with all JavaScript arrays, the first item has an index of 0. So, in this example, the first option, which reads "--SELECT A STATE--" is option 0.

The selectedIndex Property

Select menus have a selectedIndex property that holds the index of the currently selected option. For example, in the sample above, if North Carolina is selected, State.selectedIndex would hold 5. To see if the first option of a select menu is selected, check if selectedIndex is 0.

Let's look at the code above in detail.

  1. The "GO" button has an onclick event handler that, when clicked, passes the State select menu to the jumpMenu() function.
    <input type="button" value="GO" onclick="jumpMenu(this.form.State);">
  2. The jumpMenu() function does three things:
    1. Creates the variable i that holds the selectedIndex property of the passed-in select menu.
    2. Creates the variable selection that holds the value of the selected option.
    3. Checks to see if the first option is selected.
      • If it is, the function alerts the user to select an option.
      • If it is not, the function creates a variable, url, to hold the destination page and then loads that page by changing the href property of the location object to url.

Disabling Form Elements

Form elements can be disabled by setting the element's disabled property to true. They can be re-enabled by setting the disabled property to false.

Syntax
FormElement.disabled = true;
FormElement.disabled = false;

The example below is a modified version of the jump menu that disables the "GO" button unless a state is selected.

Code Sample: DynamicForms/Demos/JumpMenus2.html

<html>
<head>
<title>Jump Menus</title>
<script type="text/javascript">
function jumpMenu(select){
 var i = select.selectedIndex;
 var selection = select.options[i].value;
 var url = "http://www.50states.com/" + selection + ".htm";
 location.href = url;
}

function toggleButton(form){
 if (form.State.selectedIndex === 0) {
  form.btnJump.disabled = true;
 } else {
  form.btnJump.disabled = false;
 }
}
</script>
</head>
<body onload="ToggleButton(document.forms[0]);">
<form>
 <select name="State" onChange="toggleButton(this.form);">
  <option value="0">--SELECT A STATE--</option>
  <option value="alabama">Alabama</option>
  <option value="illinois">Illinois</option>
  <option value="massachu">Massachusetts</option>
  <option value="montana">Montana</option>
  <option value="ncarolin">North Carolina</option>
  <option value="wvirgini">West Virginia</option>
 </select>
 <input type="button" name="btnJump" value="GO" 
   onclick="jumpMenu(this.form.State);">
</form>
</body>
</html>
Code Explanation

Notice that the jumpMenu() function no longer checks if a state has been selected. It is only called when the user clicks the "Go" button, which is only enabled if a state is selected.

Interdependent Select Menus

Interdependent select menus allow you to populate one select menu based on a choice made in another select menu. For example, a menu of cities might change based on the state that was selected in another menu, as shown in the following example.

Code Sample: DynamicForms/Demos/Interdependent.html

<html>
<head>
<title>Interdependent Select Menus</title>
<script type="text/javascript">
var NEW_YORKERS = [];
var CALIFORNIANS = [];

NEW_YORKERS[0] = new Option("New York City", "NYC");
NEW_YORKERS[1] = new Option("Syracuse", "SYR");
NEW_YORKERS[2] = new Option("Albany", "ALB");
NEW_YORKERS[3] = new Option("Rochester", "ROC");

CALIFORNIANS[0] = new Option("Los Angeles", "LAN");
CALIFORNIANS[1] = new Option("San Diego", "SDI");
CALIFORNIANS[2] = new Option("San Francisco", "SFR");
CALIFORNIANS[3] = new Option("Oakland", "OAK");

function populateSub(mainSel, subSel){
 var mainMenu = mainSel;
 var subMenu = subSel;
 var subMenuItems;
 subMenu.options.length = 0;

 switch (mainMenu.selectedIndex) {
 case 0:
  subMenuItems = NEW_YORKERS;
  break;
 case 1:
  subMenuItems = CALIFORNIANS;
  break;
 }

 for (var i = 0; i < subMenuItems.length; i++) {
  subMenu.options[i] = subMenuItems[i];
 }
}

</script>
</head>
<body>
<form name="Menus">
 <select name="State" onchange="populateSub(this, this.form.City);">
  <option value="NY">New York</option>
  <option value="CA">California</option>
 </select>
 <select name="City">
  <option value="NYC">New York City</option>
  <option value="SYR">Syracuse</option>
  <option value="ALB">Albany</option>
  <option value="ROC">Rochester</option>
 </select>
</form>
</body>
</html>
Code Explanation

Let's look at the code above in detail.

  1. As the page loads, two arrays (NEW_YORKERS and CALIFORNIANS) are created and then populated with Options using the Option() constructor. The Option() constructor takes four parameters: text, value, defaultSelected, and selected. Only text is required.
  2. The body of the page contains a form with two select menus: State and City. When a state is selected, the onchange event handler triggers a call to the populateSub() function, passing in the State menu as mainSel and the City menu as subSel.
  3. A few variables are created and then the City menu is emptied with the following code.
    subMenu.options.length = 0;
  4. A switch statement based on the option selected in the main menu is used to determine the array to look in for the submenu's options.
    switch (mainMenu.selectedIndex) {
    case 0:
     arrSubMenu = NEW_YORKERS;
     break;
    case 1:
     arrSubMenu = CALIFORNIANS;
     break;
    }
  5. A for loop is used to loop through the array populating the submenu with options.

Making the Code Modular

A problem with the code in DynamicForms/Demos/Interdependent.html is that it would need to be modified in several places to add or change options. This next example, though more complex, is much more modular, and hence, reusable.

Code Sample: DynamicForms/Demos/Interdependent2.html

<html>
<head>
<title>Interdependent Select Menus</title>
<script type="text/javascript">
var MENU = [];
MENU[0] = [];
MENU[1] = [];

MENU[0][0] = new Option("New York", "NY");
MENU[0][1] = new Option("New York City", "NYC");
MENU[0][2] = new Option("Syracuse", "SYR");
MENU[0][3] = new Option("Albany", "ALB");
MENU[0][4] = new Option("Rochester", "ROC");

MENU[1][0] = new Option("California", "CA");
MENU[1][1] = new Option("Los Angeles", "LAN");
MENU[1][2] = new Option("San Diego", "SDI");
MENU[1][3] = new Option("San Francisco", "SFR");
MENU[1][4] = new Option("Oakland", "OAK");
 
function populateMain(mainSel, subSel){
 var mainMenu = mainSel;
 var subMenu = subSel;
 mainMenu.options.length = 0;
 for (var i = 0; i < MENU.length; i++) {
  mainMenu.options[i] = MENU[i][0];
 }
 populateSub(mainMenu, subMenu);
}

function populateSub(mainSel, subSel){
 var mainMenu = mainSel;
 var subMenu = subSel;
 var optMainMenu;
 subMenu.options.length = 1;
 optMainMenu = mainMenu.selectedIndex;
 for (var i = 1; i < MENU[optMainMenu].length; i++) {
  subMenu.options[i] = MENU[optMainMenu][i];
 }
}
</script>
</head>
<body onload="populateMain(document.Menus.State, document.Menus.City);">
<form name="Menus">
 <select name="State" onchange="populateSub(this, this.form.City);"></select>
 <select name="City">
  <option value="0">--Please Choose--</option>
 </select>
</form>
</body>
</html>
Code Explanation

This example uses a two-dimensional array to hold the menus. The first item of each array holds the State options, which is used in the main menu. The rest of the items in each array hold the City options used to populate the submenu.

The State select menu starts out empty and the City menu starts out with just a single "Please Choose" option. The two functions populateMain() and populateSub() are used to populate the two menus. Both functions are completely generic and reusable.

Creating a JavaScript Timer

JavaScript timers can be used to create timed quizzes or events. The trick to a timer is to call a function recursively on a time increment.

The setTimeout() Method

The window object's setTimeout() method is used to execute a block of JavaScript code every n milliseconds. The syntax is shown below.

setTimeout("statements to execute", n);

Or

setTimeout(functionToCall, n);

The example below shows how the setTimeout() method can be used to create a timer.

Code Sample: DynamicForms/Demos/Timer.html

<html>
<head>
<title>JavaScript Timer</title>
<script type="text/javascript">

var SECONDS_LEFT, TIMER, TIMES_UP;
function init(){
 document.Timer.btnStart.disabled = true;
}

function resetTimer(seconds){
 SECONDS_LEFT = seconds;
 document.Timer.TimeLeft.value = SECONDS_LEFT;
 clearTimeout(TIMER);
 document.Timer.btnStart.disabled = false;
 document.Timer.btnReset.disabled = true;
}

function decrementTimer(){
 TIMES_UP = false;
 document.Timer.TimeLeft.value = SECONDS_LEFT;
 document.Timer.btnStart.disabled = true;
 document.Timer.btnReset.disabled = false;
 SECONDS_LEFT--;
 if (SECONDS_LEFT >= 0) {
  TIMER = setTimeout(decrementTimer, 1000);
 } else {
  alert("Time's up!");
  resetTimer(10);
 }
}
</script>
</head>
<body onload="init();">
<form name="Timer" onsubmit="return false;">
Timer: <input type="text" name="TimeLeft" size="2"
  style="text-align:center" onfocus="this.blur();">
  seconds left<br>
  <input type="button" name="btnStart" 
   value="Start" onclick="decrementTimer();">
  <input type="button" name="btnReset" 
   value="Reset" onclick="resetTimer(10);">
</form>
</body>
</html>
Code Explanation

Let's look at the code above in detail.

  1. As the page loads, three global variables are created: SECONDS_LEFT to hold the number of seconds left, TIMER - to hold the timer, and TIMES_UP - to flag if the timer has run out.
    var SECONDS_LEFT, TIMER, TIMES_UP;
  2. The body of the page contains a form with a text field holding the number of seconds left, a "Start" button and a "Reset" button.
    <form name="Timer" onsubmit="return false;">
    Timer: <input type="text" name="TimeLeft" size="2"
      style="text-aliagn:center" onfocus="this.blur();">
      seconds left<br>
      <input type="button" name="btnStart" 
       value="Start" onclick="decrementTimer();">
      <input type="button" name="btnReset" 
       value="Reset" onclick="resetTimer(10);">
    </form>
  3. The onload event handler of the body tag triggers the init() function, which disables the "Start" button.
    function init(){
     document.Timer.btnStart.disabled = true;
    }
  4. When the user clicks on the "Reset" button, the resetTimer() function is called. This function does the following:
    • Sets SECONDS_LEFT to the number passed into the function.
      SECONDS_LEFT = seconds;
    • Sets the value of the TimeLeft text field to SECONDS_LEFT.
      document.Timer.TimeLeft.value = SECONDS_LEFT;
    • Clears the TIMER timer.
      clearTimeout(TIMER);
    • Enables the "Start" button.
      document.Timer.btnStart.disabled = false;
    • Disables the "Reset" button.
      document.Timer.btnReset.disabled = true;
  5. When the user clicks on the "Start" button, the decrementTimer() function is called. This function does the following:
    • Sets TIMES_UP to false.
      TIMES_UP = false;
    • Sets the value of the TimeLeft text field to SECONDS_LEFT.
      document.Timer.TimeLeft.value = SECONDS_LEFT;
    • Disables the "Start" button.
      document.Timer.btnStart.disabled = true;
    • Enables the "Reset" button.
      document.Timer.btnReset.disabled = false;
    • Decrements SECONDS_LEFT by one.
      SECONDS_LEFT--;
    • Checks to see if SECONDS_LEFT is greater than or equal to zero.
      if (SECONDS_LEFT >= 0) {
       TIMER = setTimeout(decrementTimer, 1000);
      } else {
       alert("Times up!");
       resetTimer(10);
      }
      • If SECONDS_LEFT is greater than or equal to zero, setTimeout() is used to re-call decrementTimer() after 1000 milliseconds (1 second). This creates a timer object, which is assigned to TIMER.
      • If SECONDS_LEFT is less than zero, an alert pops up notifying the user that time is up and resetTimer(), which clears the timer, is called.

A Sample Quiz Tool

The following example brings together the concepts learned in this lesson to create a quiz tool. The quiz looks like this:

Code Sample: DynamicForms/Demos/MathQuiz.html

<html>
<head>
<title>Math Quiz</title>
<script type="text/javascript" src="Select.js"></script>
<script type="text/javascript">

var MENU = [];
var SECONDS_LEFT, TIMER, TIMES_UP, TOTAL_TIME = 10;

function init(){
 MENU[0] = [];
 MENU[1] = [];
 MENU[2] = [];
 MENU[3] = [];
 
 MENU[0][0] = new Option("Addition");
 MENU[0][1] = new Option("5 + 4", "9");
 MENU[0][2] = new Option("9 + 3", "12");
 MENU[0][3] = new Option("7 + 12", "19");
 MENU[0][4] = new Option("13 + 24", "37");

 MENU[1][0] = new Option("Subtraction");
 MENU[1][1] = new Option("5 - 1", "4");
 MENU[1][2] = new Option("12 - 4", "8");
 MENU[1][3] = new Option("23 - 11", "12");
 MENU[1][4] = new Option("57 - 19", "38");
 
 MENU[2][0] = new Option("Multiplication");
 MENU[2][1] = new Option("1 * 3", "3");
 MENU[2][2] = new Option("4 * 8", "32");
 MENU[2][3] = new Option("7 * 12", "84");
 MENU[2][4] = new Option("13 * 17", "221");
 
 MENU[3][0] = new Option("Division");
 MENU[3][1] = new Option("4 / 1", "4");
 MENU[3][2] = new Option("12 / 3", "4");
 MENU[3][3] = new Option("21 / 7", "3");
 MENU[3][4] = new Option("121 / 11", "11");

 populateMain(document.Quiz.Operator, document.Quiz.Question);
 resetTimer(TOTAL_TIME);
 document.Quiz.btnCheck.disabled = true;
 document.Quiz.Answer.disabled = true;
}

function resetTimer(seconds){
 TIMES_UP = true;
 SECONDS_LEFT = seconds;
 document.Quiz.TimeLeft.value = SECONDS_LEFT;
 clearTimeout(TIMER);
 document.Quiz.Answer.value = "";
}

function decrementTimer(){
 TIMES_UP = false;
 document.Quiz.TimeLeft.value = SECONDS_LEFT;
 SECONDS_LEFT--;
 if (SECONDS_LEFT >= 0) {
  TIMER = setTimeout(decrementTimer, 1000);
 } else {
  alert("Time's up!  The answer is " + getAnswer() + ".");
  resetTimer(TOTAL_TIME);
 }
}

function checkAnswer(answer){
 var correctAnswer = getAnswer();
 if (answer === correctAnswer) {
  alert("Right! The answer is " + correctAnswer + ".");
 } else {
  alert("Sorry. The correct answer is " + correctAnswer + ".");
 }
 removeOption();
 questionChange();
}

function removeOption(){
 var i = document.Quiz.Operator.selectedIndex;
 var j = document.Quiz.Question.selectedIndex;
 MENU[i].splice(j, 1);
 if (MENU[i].length == 1) {
  MENU.splice(i, 1);
  if (MENU.length === 0) {
   endQuiz();
  }
 }
 populateMain(document.Quiz.Operator, document.Quiz.Question);
 resetTimer(TOTAL_TIME);
}

function questionChange(){
 if (document.Quiz.Question.selectedIndex === 0) {
  document.Quiz.btnCheck.disabled = true;
  document.Quiz.Answer.disabled = true;
  resetTimer(TOTAL_TIME);
 } else {
  document.Quiz.btnCheck.disabled = false;
  document.Quiz.Answer.disabled = false;
  decrementTimer();
 }
}

function endQuiz(){
 resetTimer(TOTAL_TIME);
 alert("Thanks for playing! The quiz will now reload.");
 init();
}

function getAnswer(){
 var i = document.Quiz.Question.selectedIndex;
 var answer = document.Quiz.Question[i].value;
 return answer;
}

</script>
</head>
<body onload="init();">
<form name="Quiz" onsubmit="return false;">
<table border="1" cellspacing="0" cellpadding="4" align="center">
<tr>
 <td>Category:</td>
 <td>
 <select name="Operator" 
  onchange="populateSub(this, this.form.Question);
     resetTimer(TOTAL_TIME);">
 </select>
 </td>
</tr>
<tr>
 <td>Question:</td>
 <td>
  <select name="Question"
   onchange="questionChange();">
   <option value="0">--Please Choose--</option>
  </select>
 </td>
</tr>
<tr>
 <td>Answer:</td>
 <td>
  <input type="text" name="Answer" size="2">
  <input type="button" name="btnCheck" value="Check Answer"
   onclick="checkAnswer(this.form.Answer.value);">
 </td>
</tr>
<tr>
 <td>Timer:</td>
 <td><input type="text" name="TimeLeft" size="2"
  style="text-align:center" onfocus="this.blur();">
  seconds left</td>
</tr>
</table>
</form>
</body>
</html>
Code Explanation

Here's how the quiz works:

  1. The Question select menu is always populated with questions in the indicated category.
  2. The "Check Answer" button and the Answer text field are only enabled when a question is selected.
  3. The timer starts when a question is selected and stops when it runs out or when the "Check Answer" button is clicked.
  4. When the "Check Answer" button is clicked, the user is alerted as to whether or not the answer is correct and the question is removed from the question menu.
  5. When all questions in a category are gone, the category is removed from the category menu.
  6. When all questions in all categories have been completed, the user is thanked for taking the quiz and the entire quiz is restarted.

Spend some time reviewing this code. You shouldn't see anything new, except in the way the code is designed.

Dynamic Forms Conclusion

In this lesson of the JavaScript tutorial, you have learned to build interactive, dynamic forms.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table of Contents.

Use of this website implies agreement to the following:

Copyright Information

All pages and graphics on this Web site are the property of Webucator, Inc. unless otherwise specified.

None of the content on this website may be redistributed or reproduced in any way, shape, or form without written permission from Webucator, Inc.

No Printing or saving of web pages

This content may not be printed or saved. It is for online use only.


Linking to this website

You may link to any of the pages on this website; however, you may not include the content in a frame or iframe without written permission from Webucator, Inc.


Warranties

This website is provided without warranty of any kind. There are no guarantees that use of the site will not be subject to interruptions. All direct or indirect risk related to use of the site is borne entirely by the user. All code and explanations provided on this site are provided without warranties to correctness, performance, fitness, merchantability, and/or any other warranty (whether expressed or implied).

For individual private use only

You agree not to use this online manual to deliver or receive training. If you are delivering or attending a class that is making use of this online manual, you are in violation of our terms of service. Please report any abuse to courseware@webucator.com. If you would like to deliver or receive training using this manual, please fill out the form at http://www.webucator.com/Contact.cfm.