Turning a form into a multistep process with jQuery

This post is more than 2 years old.

Byron asks:

jQuery question that I can't get my head around. I have a form with about 20 questions. The client want to show one question "per page". So instead of 20 cfm files, I thought I'd try jQuery to hide/show the questions so I'd have only one cfm page. I put "Next" buttons to proceed to next question.


Excerpt of form:

<div id="q2">
<p>2.) Question 2 <input name="Age" type="text"></p>
<input type="button" name="Next" value="Next" id="Next2" />
</div>


<div id="q3">
<p>2.) Question 3 <input name="Birthplace" type="text"></p>
<input type="button" name="Next" value="Next" id="Next3" />
</div>

My jQuery is like so:

$('#Next2').click(function(){
$('#q2').hide();
$('#q3').show();
})
$('#Next3').click(function(){
$('#q3').hide();
$('#q4').show();
})

Works like I want it to. Now the question. Is there way to create a function for this so I don't have to do 20 functions. I tried some ways using .parentNode and .nextSibling with no avail.

Before I had a chance to answer, Bryon came back with a partial solution:

I was able to clean the code up a bit like so:

$('#Next2,#Next3').click(function(){
$(this).parent().hide();
$(this).parent().next().show();
})

So now I would need to list each ID selector (Next2-Next20) in the selector. Would there be a way to clean that up?

I decided to try to tackle this solution a different way. First, I decided that I did not want to have to add buttons to each question. I thought this would make the form a bit simpler and give us more control over the "pagination":

<form id="mainform" method="post">

<div class="question">

  1. Why do you rock, Raymond? <input type="text" name="whyrock"> </div>

<div class="question"> 2) A radio question:<br/> <input type="radio" name="q2" value="a">Apples<br/> <input type="radio" name="q2" value="b">Bananas<br/> </div>

<div class="question"> 3) Another dumb question: <input type="text" name="q3"> </div>

<div class="question"> 4) A textarea question:<br/> <textarea name="foo"></textarea> </div>

</form>

Note that I've made use of a class on each div called question. To help create a pagination effect, I then added this style:

<style> .question { display:none; } </style>

Now let's look at the jQuery I ended up with:

$(document).ready(function() { //add the Next button $('.question').append("<br/><input type='button' value='Next' class='questionBtn'>")

//show q1
$('.question:first').show()

$('.questionBtn').click(function(){
	//new logic here - am i the last one?
	if($(this).parent().is(":last-child")) {
		$("#mainform").submit()
	}
	$(this).parent().hide();
	$(this).parent().next().show();
})

})

I begin by finding all my question divs and appending a Next button to them. This saves me some work right there. Since I previously hid all my questions, I now show the first one. Finally, I've modified Bryon's code a bit to handle the buttons. His code actually worked perfectly fine - but I wanted to make sure that the last button would perform a form submit. (In fact, it occurs to me I could also make the last button label read 'Submit' instead of 'Next' if I wanted to as well.) I use the is() function to compare the node to the last one - and if they match - perform a submit. (Thank you, StackOverflow: How to check for DOM equality with jQuery?)

How well does it work? Check the demo yourself:

You can view source to see the complete HTML there. Anyone else done something like this? I'll note that I wrote this in like five minutes so I'm sure there are things that can be improved.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Michael Evangelista posted on 5/27/2010 at 11:16 AM

Here's a multipart form i did as part of one of my first jquery-based projects, which made it into the jQuery docs: http://docs.jquery.com/Plug...

the trick here - and the reason joern wanted to use it in the demos - was validating each section before allowing the user to progress to the next (as opposed to validating the whole form on submit), meanwhile, allowing for all of the next/back stuff to work between steps

Comment 2 by Josh Curtiss posted on 5/27/2010 at 12:39 PM

I've done something similar to this. I had multiple forms, one form for each step in the form. Then I would just hide/display the appropriate form as I went. I guess there's no fundamental difference between multiple forms or multiple divs, since the final action in the end was an AJAX call anyway.

I find myself coding this way more after having learned Flex... I love having all the "screens" loaded to have that instantaneous response when the user clicks "Next" or whatever.

Comment 3 by Byron Raines posted on 5/27/2010 at 5:20 PM

Thanks Ray. Exactly what I was looking for. Works perfectly. Much cleaner. Glad that I was on the right track. Would it be better to do an if statement to append input tag with value="Submit" or if statement just to change value to "submit" after the input statement has been appended?

@Michael Validation was the next step. I'll look at that post.

Thanks

byron

Comment 4 by Bobby Jack posted on 5/27/2010 at 5:49 PM

For usability, you should probably have a submit button in your markup, add an action to your form, and only hide your questions via javascript, not CSS. This would allow the form to work if javascript is not available.
Ironically, this comment form only works with javascript enabled, too! :-)

Comment 5 by Sean posted on 5/27/2010 at 5:57 PM

Cool stuff! My only complaint is that semantically it would be better to use fieldsets instead of divs to wrap each individual question.

Comment 6 by Dave H posted on 5/27/2010 at 6:08 PM

Great tutorial, but please use fieldset and label elements instead of div's and p's!

Comment 7 by Jamie Thompson posted on 5/27/2010 at 6:25 PM

Maybe it's just my OCD talking, but with brevity in mind you could also do the following:

$('.question').append("<br/><input type='button' value='Next' class='questionBtn'>").eq(0).show();

Comment 8 by Phillip Senn posted on 5/27/2010 at 6:41 PM

At Google I/O, they demonstrated a expense app that did a slide left and slide right to transition between pages. I know there is a slide up and down built into jQuery, but how do you slide left and right?

Comment 9 by Grant posted on 5/27/2010 at 6:58 PM

Here's *my* OCD piping up:

$(document).ready(function() {});

is the same as:

$(function() {});

save your fingers

Comment 10 by Raymond Camden posted on 5/27/2010 at 10:09 PM

@Sean/Dave: To be honest, I keep forgetting about fieldset. Good point though.

@To Both OCD Guys - Yes - nice - I'm OCD most of the time. ;)

@Phillip Senn - you can easily do transitions in jQuery. I tend to hate em though. A transition is nice once - not after that.

Comment 11 by Raymond Camden posted on 5/27/2010 at 10:10 PM

@Phillip Senn - Ok, I lie - this is a cool mod:

$(this).parent().next().fadeIn('slow');

Comment 12 by Dave posted on 5/28/2010 at 3:38 AM

Couldn't the click handler just be reduced to this one liner?

$(this).parent().hide().next().show().length || $("#mainform").submit();

Or use an if on !length if you prefer.

Comment 13 by Tom Sucaet posted on 5/28/2010 at 3:31 PM

I have some great experience with the jQuery FormWizard plugin:
http://plugins.jquery.com/p...
It also works great with the jQuery validation plugin and you can even add transition animation between the form steps.

Comment 14 by Paul Baylis posted on 7/15/2010 at 9:10 AM

@Tom, or anyone else who may know:
I've had a fiddle with <a href="http://thecodemine.org/">jQuery Form Wizard</a> and built a multi-page validating form. However, I don't know how to access and use the form data that it posts. See my <a href="http://www.catholicpages.co...">working example here</a> .

My form currently posts to a cfm file, which has a basic insert query, but I don't know what the data looks like or how to reference it in order to insert it. The FormWizard site doesn't provide much help and I see two other people have asked this same question on the jQuery forum but no-one's answered.

Any help appreciated immensely.

Comment 15 by Paul Baylis posted on 7/15/2010 at 9:12 AM

Sorry, I didn't realise the blog automatically formats URLs.

Working example: http://www.catholicpages.co...

Comment 16 by Paul Baylis posted on 7/16/2010 at 12:37 AM

OK, the answer is that the form input variables are automatically available in the "form" scope of the page specified in the form "action" attribute.

Comment 17 by Raymond Camden posted on 7/17/2010 at 7:27 AM

Don't forget you can cfdump to a file. Just do that for the FORM scope and look at the values when the file is written out.

Comment 18 by Karolus posted on 2/21/2011 at 6:50 AM

I want to have the questions as shown here, but if I have a question, whose answers create a branch, to other questions, how would this be done with this code?

Comment 19 by Raymond Camden posted on 2/21/2011 at 7:12 AM

With the code as is - no - it can't be done. You would need to customize the code above.