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":
<div class="question"> <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>
<form id="mainform" method="post">
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:
//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();
})
})
$(document).ready(function() {
//add the Next button
$('.question').append("<br/><input type='button' value='Next' class='questionBtn'>")
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.
Archived Comments
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
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.
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
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! :-)
Cool stuff! My only complaint is that semantically it would be better to use fieldsets instead of divs to wrap each individual question.
Great tutorial, but please use fieldset and label elements instead of div's and p's!
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();
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?
Here's *my* OCD piping up:
$(document).ready(function() {});
is the same as:
$(function() {});
save your fingers
@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.
@Phillip Senn - Ok, I lie - this is a cool mod:
$(this).parent().next().fadeIn('slow');
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.
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.
@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.
Sorry, I didn't realise the blog automatically formats URLs.
Working example: http://www.catholicpages.co...
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.
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.
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?
With the code as is - no - it can't be done. You would need to customize the code above.