Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at Scotch On The Rock (SOTR) 2010 (London) with:

Ask Ben: Showing Related Form Fields Based On A Given Selection

By Ben Nadel on

Happy Holidays! I am trying to finish a input form in my website but I am no clue How do it, Please, Can you help me? The page is PHP contact form, the issue is when a visitor select option 1 then the form need to ask (and show) for input 1, input 2; if the visitor select option 2 the form need to ask (and show) for input 3. Before the option 1 or option 2 is clicked or selected the input 1, 2 and 3 keep hide. I appreciate a lot if you can help me. Thanks!

I am not a PHP developer, so I am not going to show you any server-side scripts; but, I can show you how to make your form dynamic based on the given selection. The following demo uses jQuery to power the DOM manipulation; but, before I show you what I did, I have to bring up the point that the if the user does not have Javascript enabled, you should probably have a way to process the form on the server regardless of the goodness we are about to add.

 
 
 
 
 
 
 
 
 
 

That said, I created a small demo in which the value of a given select box changes the list of available checkboxes. Not only do some of the input gets hidden, they are also disabled such that they will not be submitted along with the form data collection.

  • <!DOCTYPE HTML>
  • <html>
  • <head>
  • <title>Showing Related Fields With jQuery</title>
  • <script type="text/javascript" src="jquery-1.4a2.js"></script>
  • <script type="text/javascript">
  •  
  • // When the DOM is loaded, init scripts.
  • jQuery(function( $ ){
  •  
  • // Get a reference to the seeking input box.
  • var seeking = $( "#seeking" );
  •  
  • // Ge a reference to the male and female attribute
  • // lists. These are the elements that will be shown
  • // and hidden depending on the seeking value.
  • var maleAttributes = $( "#maleAttributes" );
  • var femaleAttributes = $( "#femaleAttributes" );
  •  
  • // Remove the titles that were in the page ONLY if
  • // Javascript was not enabled.
  • $( "h2.attribute-title" ).remove();
  •  
  • // Bind the onChange event of the select box. If the
  • // user selects "Female" we want ot show the female
  • // attributes list and vice-versa for Male.
  • seeking.change(
  • function( event ){
  •  
  • // Check to see what the current value of the
  • // seeking input is.
  • if (seeking.val() == "F"){
  •  
  • // FEMALE selected.
  •  
  • // Show the female list and re-enable any
  • // input fields within it.
  • femaleAttributes
  • .show()
  • .find( ":input[ disabled ]" )
  • .removeAttr( "disabled" )
  • ;
  •  
  • // Hide the male list and disable any
  • // inputs within it so that they cannot be
  • // submitted with the form.
  • maleAttributes
  • .hide()
  • .find( ":input" )
  • .attr( "disabled", "true" )
  • .removeAttr( "checked" )
  • ;
  •  
  • } else {
  •  
  • // MALE selected.
  •  
  • // Show the male list and re-enable any
  • // input fields within it.
  • maleAttributes
  • .show()
  • .find( ":input[ disabled ]" )
  • .removeAttr( "disabled" )
  • ;
  •  
  • // Hide the female list and disable any
  • // inputs within it so that they cannot be
  • // submitted with the form.
  • femaleAttributes
  • .hide()
  • .find( ":input" )
  • .attr( "disabled", "true" )
  • .removeAttr( "checked" )
  • ;
  •  
  • }
  • }
  • );
  •  
  •  
  • // Now that we have the onChange event bound to the
  • // select box, manually trigger it to make sure the
  • // form is in the appropriate state.
  • seeking.change();
  •  
  • });
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • Showing Related Fields With jQuery
  • </h1>
  •  
  • <form>
  •  
  • <p>
  • I am a:
  •  
  • <select>
  • <option selected="true">Male</option>
  • <option>Female</option>
  • </select>
  •  
  • seeking a:
  •  
  • <select id="seeking">
  • <option value="M">Male</option>
  • <option value="F" selected="true">Female</option>
  • </select>
  • </p>
  •  
  • <p>
  • I prefer the following attributes:
  • </p>
  •  
  •  
  • <!---
  • This title will be removed with Javascript. It is here
  • only to make the page readable if Javascript is not
  • enabled in the user's browser.
  • --->
  • <h2 class="attribute-title">
  • Male Attributes
  • </h2>
  •  
  • <!---
  • These are the only attributes that should be visible
  • if the above "seeking" select box is Male.
  • --->
  • <ul id="maleAttributes">
  • <li>
  • <label>
  • <input type="checkbox" />
  • Facial Hair
  • </label>
  • </li>
  • <li>
  • <label>
  • <input type="checkbox" />
  • Muscles
  • </label>
  • </li>
  • </ul>
  •  
  •  
  • <!---
  • This title will be removed with Javascript. It is here
  • only to make the page readable if Javascript is not
  • enabled in the user's browser.
  • --->
  • <h2 class="attribute-title">
  • Female Attributes
  • </h2>
  •  
  • <!---
  • These are the only attributes that should be visible
  • if the above "seeking" select box is Female.
  • --->
  • <ul id="femaleAttributes">
  • <li>
  • <label>
  • <input type="checkbox" />
  • Long Hair
  • </label>
  • </li>
  • <li>
  • <label>
  • <input type="checkbox" />
  • Long Nails
  • </label>
  • </li>
  • </ul>
  •  
  •  
  • <p>
  • <input type="submit" value="Search" />
  • </p>
  •  
  • </form>
  •  
  • </body>
  • </html>

As you can see in the above code, the HTML page contains sub-headers for the two sets of attribute lists. These are there to make the page usable and less confusing if the user does not have Javascript enabled. If the user does have Javascript enabled, however, the H2 elements are quickly removed from the visible elements and the two unordered lists are bound to the value of the "seeking" select box.

Using jQuery, we bind an event listener to the onChange event of our "seeking" select box. Then, immediatly after binding the event listener, we manually trigger the change event on the select box. This will invoke our event handler which will update the DOM accordingly. While this is not entirely necessary, I find that it keeps the HTML cleaner and delegates the Javascript-related manipulation entirely in the Javascript which, in turn, relieves us from having to put too much additional markup in our HTML.

If this is your first time seeing jQuery, this might look a bit confusing. jQuery is a Javascript library that helps keep event handling and DOM manipulation about as simple as it can be. I highly recommend looking into it. I hope that this helps point you in the right direction.



Reader Comments

Can you elaborate a bit further on 'seeking.change();'? I bind a LOT of my form elements using jQuery and always get frustrated when I have another method change a select box and of course THAT change doesn't fire the ".change() binding". Let me know if that makes any sense at all. :)

Reply to this Comment

@Ryan (rehashed from our private convo),

I completely understand the frustration. Really, what we are seeing here is that programmatic changes to form elements don't trigger the events that are implicitly triggered by user interactions. While this does lead to some extra manual triggering, I have to imagine that they did this as a safe-guard.

Take the following trite example:

var form = $( "form" );

form.submit(
function(){
setTimeout( function(){ form.submit(); }, 1000 );
return( false );
}
);

In this case, we are trapping the implicit form submission, cancelling it, and then submitting the form 1 second later. If the programmatic execution of the "submit" action, in turn, triggered the implicit "submit" event, then we would quickly get into a infinite loop of form submission handling.

However, aside from the safe-guard against things like this, I am sure there is much more philosophy that goes into it. In an event-driven environment (such as with a UI), the "event" is what ties the interaction to the code-behind; however, if you explicitly do something programmatically, there is no longer an "event" that needs to tie the UI interaction to the code.

... but, this is all just my stream of consciousness; I cannot be sure why it is the way it is. Maybe Wikipedia has something juicy.

Reply to this Comment

@Ben -- Very well put. It absolutely makes sense why it would work this way. I definitely had a feeling there was a reason to the madness, and this is a pretty good reason. My worry was that I was simply overlooking a special set of event names that I could use, or maybe a global jQuery setting I could set.

The good news is, proper code abstraction will allow for the ease of manual triggers to each event, so it's all good.

Thanks again for the fine work, sir.

Reply to this Comment

Hi, I am the person who asked you this question and after days to work on it,
Sorry for the delay, but I was out of the country.

Finally, Thanks to your very detailed post and explication, I did it!!!!, I included this jquery and VOALA!!! the PHP form now works!.

Deep thanks and sincere gratitude, you rocks!!
Not only because you have the knowledge also because you care about us.

I am web and graphic designer, if you need something, Just ask!!!

Heather

Reply to this Comment

Do you know which is the better way to include in the form a confirmation page, which offers to the visitant 2 options?

1.- Edit the info submitted (goes to the previous page keeping the data previous entered).

2.- Send the info to an email address (this I already know How to do it in PHP).
Can you help me with this?

Thanks!?????

Reply to this Comment

@Heather,

For confirmations, I tend to go with a confirmation page (separate from the form) with an optional email (depending on what data I might want the user to have for their records).

Reply to this Comment

Thanks Ben!

Let me start making the confirmation page, the problem is I have no clue How or where to save the data when the user go back to the form.

Reply to this Comment

@Heather,

I am not sure what you mean; why do you need to take the user back to the form *after* the confirmation?

Reply to this Comment

Sorry for my english, let me explain.

After the user fill out all the fields in the form and click submit, the confirmation page appear with all the data the user filled.

In this page I need to include the option to change the info submitted.

If the user wants change the info he will need go to the previous page keeping the data was entered.

This process (keeping the data) I have no clue how to do it.

Please, let me know if I explain better.

Thanks!

Reply to this Comment

@Heather Try saving each value to the session scope. This can be done on your confirmation page by doing something like....

cfset session.firstName = form.firstName

Then, on your form page you can test to see if session.firstName is defined, and if so, display it in the field's value...

cfif isDefined(session.firstName)
#session.firstName#
/cfif

...of course I left out all of the bracket tags since I'm not sure if this form will strip them out anyways.

Reply to this Comment

@Heather,

@Ryan has the right idea. Saving it in the session is gonna be the easiest way to do. Sometimes, when you do something like this, it's helpful to think of it as a "mutli-step" form; even, if it's only two steps:

1. Form
2. Confirmation

In such situations, you can create session-based data that is "form process" specific. For more information on what I mean, take a look at this:

http://www.bennadel.com/blog/1265-Multi-Step-Form-Demo-In-ColdFusion.htm

It allows you to package the form process based on a single ID (typically a UUID), that can easily be passed back and form between form pages.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.