This page has been archived. For the latest news on FormAssembly, go to: http://www3.formassembly.com/blog

The Switch Behavior Explained

Update: Comments are closed for this post, but you can go to the wForms forum if you have any question or comment. Thanks !

 

This post is part of the wForms Documentation. wForms is an open-source javascript library that adds commonly needed behaviors to traditional web forms without the need for any programming skill.

For additional help, visit the wForms forum.

The Switch behavior tackle one of the most common problem in web forms: How to display only the relevant parts of a form and hide the rest.

Let’s say I want you to subscribe to my imaginary newsletter. I need:

  1. Your agreement
  2. Your email

But it doesn’t make sense to ask for your email address if you don’t want the newsletter in the first place, right ? With the Switch behavior I can ask for your email only if you check the ‘I want to…’ box.

Go ahead, check the box:

Newsletter Subscription

It’s time for some definitions:

  • The switch is the checkbox.
    The switch operates on a target which can be turned on and off.
  • The target is the email input field.
    The target is visible only when the switch is activated.
  • Since you can have several switches and targets on one page, we need to identify a switch and its target(s) by name. For example ‘NewsletterOptin’.

Now let’s implement our Switch in 3 small steps .

  1. Enable the wForms extension by adding the following code to the <head> element of your page:

    <script type="text/javascript" src="wforms.js" ></script>

  2. Add the ’switch-NewsletterOptin’ class to your checkbox.

    <input type="checkbox" ... class="switch-NewsletterOptin" />

  3. Add the ‘offstate-NewsletterOptin’ class to your target. Because the target is actually the input field and the label, we need to nest them within a div.

    <div class='offstate-NewsletterOptin‘><label … > … </label> <input … /></div>

The switch is now operational, but we are not done yet.

What happens behind the scene is really simple. When you check the box, the div class turns to ‘onstate-NewsletterOptin‘.
How this visually affects the form really depends on your CSS. If you want the show/hide effect, add these 2 rules to your stylesheet.

.offstate-NewsletterOptin { display: none; }
.onstate-NewsletterOptin { display: block; }

If you want the switch to have a different kind of effect, just change your CSS.

That’s all folks.

Note: The name ‘NewsletterOptin’ is just an example. You can use anything as long as you are consistent: ’switch-somename’, ‘offstate-somename’, ‘onstate-somename’. If you use the form builder you will only get to choose a letter between A and K.

 

Update: Comments are now closed for this post, but you can go to the wForms forum if you have any question or comment. Thanks !

51 Responses to “The Switch Behavior Explained”

  1. Graham Says:

    Any way to get this to work with the label as well? The form has the checking functionality with the label element, but doesn’t show the extra field if you only click on the label (at least in Firefox 1.0.2 on PC).

  2. cedsav Says:

    Graham, good catch.

    Opera and IE do fire the ‘onclick’ event when the label is clicked. It should also work for Firefox, I’ll investigate this.

  3. cedsav Says:

    Interesting situation. When you click on a label, Firefox, IE and Opera correctly fire the onclick event of the associated input. But they don’t agree on the source of the event. For Firefox, it is the label element. For IE and Opera, the source is the input.

    Anyhow, that problem is now taken care of in wForms extension.

  4. Graham Says:

    Awesome. Thanks for looking into it!

  5. steve Says:

    Awesome. Is there a way to implement the switch behavior with a jump menu? I was thinking perhaps use , and then enter the function arguments in the option tage , but that doesn’t seem to work at all. Lil’ help?

  6. cedsav Says:

    Steve,

    You can add a switch class to the option tags. I updated this form to give you an example:
    http://formassembly.com/form-view.php?formID=106

    The html looks like this:
    <select id="whatever" name="whatever">
    <option value="">Please select</option>
    <option value="1" class="switch-b">Show Fieldset 1</option>
    <option value="2" class="switch-c">Show Fieldset 2</option>
    <option value="3" class="switch-d">Show Fieldset 3</option>
    </select>

    Is that answering your question ?

  7. Scott Says:

    Is there a way I can refresh a child element’s state manually? I’m trying to implement nested switches as an extension, and have all the ‘nesting’ logic added in, but just need to know what function to call to force the nesting action.

  8. cedsav Says:

    Scott, I’m not sure I understand what you need. wForms supports nested switch, I updated this form to demonstrate it.

    If you change the value of a switch programmatically, you can use the following code to update the state of the switch’s target(s):

    wf.refreshState(null, elementRef);

    …where elementRef is the reference to the switch element (as returned by getElementById(’some_switch_Id’) for instance).

    Does that help?

  9. Scott Says:

    Thanks for the quick reply. I tried the wf.refreshState(null,elementRef) and was just getting errors. Allow me to give a bit more detailed description of what I’m going for:

    Form structure:

    - Row A
    - Row B (Row A)
    - Row C (Row A & B)
    - Row D (Row A & B)
    –Table D (Row A, B & C)
    —Row DA (Row A, B & C)
    —Row DB (Row A, B & C)
    —Row DC (Row A, B & C)
    —Row DD (Row A, B & C)

    The parts in parenthesis are the requirements to be shown. All “Rows” are checkboxes, and rows in a parent table. I want all non-shown checkboxes to be unchecked. If I uncheck Row D, I want Rows DA,DB,DC & DD to be unchecked, and all of table D to be hidden. If I uncheck Row B, Rows C, D, DA, DB, DC & DD should be unchecked, and hidden, etc.

    What I added was a set of arrays to setup the parent-child relationship (inside a tag on the page), and then a custom function, triggered on the ‘onclick’, that unchecks all children of a parent when clicked. This script is working perfectly. What isn’t working perfectly is the hiding of the ‘child’ rows. This is because my script changes the checked value of the checkboxes progmamatically, so the ‘onclick’ event isn’t fired.

    The behavior I’m getting is that if I click on row A, all rows are unchecked, but only row B is hidden (it is set with offstate-A).

    I tried adding into my script a wf.refreshState(null, child), but it just gave errors in IE and weird behavior in Firefox (unrelated form elements are hiding). I also tried wf.refreshState(null,parent), but it did the same thing.

    It seems as though I need a logical eqivelence to “offstate-A && offstate-B” added to row C

  10. Ian Welsh Says:

    Hi, first off, great product. Small question though: I am finding that in my specific implementation there is a delay from clicking a radio button to the un-hiding of the element. I used the form builder function to generate it and, unfortunate for me, it worked fine on your site. But somehow in transfering it, it has created this delay. I’ve tried everything I can think of, but am not finding any errors to catch onto.

    Any help or past experience debugging would be appreciated.

    Thanks

    Ian Welsh

    The page is at: https://cme.medicine.iu.edu/members/setup.asp

  11. didier Belot Says:

    Hello,

    Fine works, thanks.

    I’ve just found a little missing piece:
    the offstate-h to offstate-j are missing in the wforms-jsonly.css provided in the zip file.

  12. cedsav Says:

    Oops. Thanks Didier.

  13. dries Says:

    Hello Cedsav,
    Thanks for your earlier response on my questions. I have a different one.
    If I’m using the switch on a checkbox to hie or display a field, I would like to set the value of this text field
    back to “” (empty) if I unclick the checkbox. This prevents me from posting information which shouldn’t be there.
    Do you have a solution?

  14. Weaver Says:

    Great job scripting all this, this switch is very clean. I had noticed the small delay mentioned earlier but I’m assuming that may have something to do with the browser rendering speed. If you’ve got a solution though, it would rock.

  15. cedsav Says:

    Weaver, the delay is (I think) mostly due to the fact that the javascript iterates the document tree to find the targets each time you click on a switch. The longer the form is, the longer it takes.

    I need the refactor the code to solve another problem (which happen when 2 different switches share the same target), and I think I will be able to improve the response time as well… but that’s pretty low in my to-do-list for now :-(

  16. dries Says:

    Hello Cedsav,
    As for my question of yesterday, I managed to get the desired effect based on a special switch function I wrote myself. It worksby comparing the value of the checkbox button to the ID of the input field. However, ofcourse, this doesn’t work when combined with the repeat class.
    Is there another way round this. I’m happy to send you my code if you want to look into it.

  17. cedsav Says:

    Dries, yes send me your code, it could be helpful.

    The problem I have with emptying a field concerns default values. Obviously when you un-switch a field, you want its value to be reverted to the default value (if any). I don’t think there’s an easy way to do that (I don’t want to use non-standard attributes), beside keeping a javascript array of references to fields and their default value.

    Your comments and others have been very helpful in determining what direction I need to go in the refactoring of the switch behavior… but it will take some time.

  18. dries Says:

    Hope this comes through better

    //hide/display elements in form field and empty value if checkbox is unchecked
    function init () {
    //search all input fields
    var aInputs = document.getElementsByTagName('input');
    for (var i = 0; i = 0) {
    //jeej, this input field has class switch_y
    aInputs[i].onclick = function() { switch_b(this); }
    switch_b(aInputs[i]);
    }
    }
    }

    function switch_b (button) {

    oValue = document.getElementById(button.value);

    // text input fields made visible
    the_substring.style.visibility = (button.checked) ? 'visible' : 'hidden';
    if (button.checked) {
    //where in the form should we show the table headers
    var the_string = button.value.charAt(0);
    // first character (note naming conventions!)
    if (the_string == "k"){
    topTabelk();
    }
    if (the_string == "b"){
    topTabelb();
    }
    if (the_string == "v"){
    topTabelv();
    }
    }
    if (!button.checked) {
    // empty fields when uncheck
    var aInputs = oValue.getElementsByTagName('input');
    for (var i = 0; i

  19. dries Says:

    A last try. I removed the smaller than sign in the code following for (var 1 = 0; i ….

    for (var i = 0; i .... aInputs.length; i++) {
    if (aInputs[i].type == "text" || aInputs[i].type == "password") aInputs[i].value = '';
    }
    }
    }

  20. dries Says:

    Last comment,

    I use this code to switch on or off different table rows after ticking a checkbox. so the field id’s differ but are the same as the value of the specific checkbox. Also I use a naming convention for the values and id’s wich gives them all a length of 9. I see your point about default values, but in this particular form I don’t use them.
    Would be very glad if you could help me out here.

  21. Didier Belot Says:

    Hello,

    some tips and ideas about the switch behavior…

    it would be very handy to define the switchScope with a className. One that may be used is the class for the paging behavior, for example.

    also, the switchState function can be optimized, in checking the nodeType before the recursive call for childNodes ;-)

  22. dries Says:

    Hello Cedsav,
    As for my question of yesterday, I managed to get the desired effect based on a special switch function I wrote myself. It worksby comparing the value of the checkbox button to the ID of the input field. However, ofcourse, this doesn’t work when combined with the repeat class.
    I use this code to switch on or off different table rows after ticking a checkbox. so the field id’s differ but are the same as the value of the specific checkbox. Also I use a naming convention for the values and id’s wich gives them all a length of 9. I see your point about default values, but in this particular form I don’t use them.
    Would be very glad if you could help me out here.
    There were mistakes in my earlier postings so I renew this. Earlier postings can be removed.
    The smaller then (
    function init () {
    //search all input fields
    var aInputs = document.getElementsByTagName(’input’);
    for (var i = 0; i = 0) {
    //jeej, this input field has class switch_y
    aInputs[i].onclick = function() { switch_b(this); }
    switch_b(aInputs[i]);
    }
    }
    }

    function switch_b (button) {

    oValue = document.getElementById(button.value);

    // text input fields made visible
    oValue.style.visibility = (button.checked) ? ‘visible’ : ‘hidden’;
    if (!button.checked) {
    // empty fields when uncheck
    var aInputs = oValue.getElementsByTagName(’input’);
    for (var i = 0; i … aInputs.length; i++) {
    if (aInputs[i].type == “text” || aInputs[i].type == “password”) aInputs[i].value = ‘’;
    }
    }
    }

  23. dries Says:

    Hello Cedsav,
    As for my question of yesterday, I managed to get the desired effect based on a special switch function I wrote myself.
    It works by comparing the value of the checkbox button to the ID of the input field. However, ofcourse, this doesn’t
    work when combined with the repeat class.
    I use this code to switch on or off different table rows after ticking a checkbox. so the field id’s differ but are the same
    as the value of the specific checkbox. Also I use a naming convention for the values and id’s wich gives them all a
    length of 9. I see your point about default values, but in this particular form I don’t use them.
    Would be very glad if you could help me out here.
    There were mistakes in my earlier postings so I renew this. Earlier postings can be removed.
    The smaller then character in the code following for (var 1 = 0; i …. has ben removed sice this causes the posting problems.
    My code

    function init () {
    //search all input fields
    var aInputs = document.getElementsByTagName(’input’);
    for (var i = 0; i = 0) {
    //jeej, this input field has class switch_y
    aInputs[i].onclick = function() { switch_b(this); }
    switch_b(aInputs[i]);
    }
    }
    }

    function switch_b (button) {

    oValue = document.getElementById(button.value);

    // text input fields made visible
    oValue.style.visibility = (button.checked) ? ‘visible’ : ‘hidden’;
    if (!button.checked) {
    // empty fields when uncheck
    var aInputs = oValue.getElementsByTagName(’input’);
    for (var i = 0; i … aInputs.length; i++) {
    if (aInputs[i].type == “text” || aInputs[i].type == “password”) aInputs[i].value = ‘’;
    }
    }
    }

  24. Prerak Says:

    Helo,

    Using the switch can I hide or display mutiple fields?

  25. cedsav Says:

    Prerak: Yes, you can. Anything inside the target element can be switched.

    In the example above, you can just add more fields inside the <div class=’offstate-NewsletterOptin >

    You should also be able to designate several elements as the target of the switch (just set the same class to each of them). Check out the Form Library for more examples.

  26. mustafa akcakaya Says:

    Hi Cedsav,

    Can i disable any field by clicking a checkbox? OR can i create a function for this?

  27. cedsav Says:

    Mustafa, the switch behavior will let you *hide* any field, without the need to write any code. Now if you want to *disable* a field (ie. the field still show up but is greyed and cannot be selected), you’ll need to write some specific code. Email me if you want more details.

  28. ayhan Says:

    Dear Sir,

    Before thank you for this great work. I want use this form like guestbook can i show the answer on the my web page?
    but i d’ont know asp or php, can i use xml for database? İf is possible you can help me. Your guestbook is very good.
    Thank you for all. I wish you good day.

    Best regards,

    Ayhan Kafadar

  29. cedsav Says:

    Ayhan, you’ll need some programming skills to process the form (PHP, ASP, or whatever is available on your website). You could use XML to store the data, but that still requires programming knowledge.

  30. Carlos Says:

    Awesome stuff!

    I need the submit button to get the submit address accordin to the choice made in Fieldset1 (dropdown list)
    I am a volunteer for a relief group and I am no programmer, so your form is just THE thing for me.

    Even if this can’t be done, you’ve already help a lot.

    thanks a bunch,

    Carlos

  31. cedsav Says:

    Carlos,

    Can you send me the link to your form (cedric at formassembly dot com) ? I’m not sure I understand what you need. Thanks.

  32. Carlos Says:

    Ced,

    I’ll do some work on it and I’ll snd it as sson as I can, either today or tomorrow.

    Thanks for your willingness to help.

    Cheers,

    Carlos

  33. Carlos Says:

    Cedric,

    I published an example of what I want (obviously not complete). I think you’ll understand.

    Is it possible to have the submit button according to the choices made?

    http://www.formassembly.com/form-view.php?formID=7506

    Cheers

    Carlos

  34. cedsav Says:

    Carlos, you’ll need to add some javascript to the page that will host the form. This should get you started:

    document.getElementById(’your_select_id’).onchange = function() {
    document.form[’your_form_name’].action = this.value; // or this.options[this.selectedIndex]?
    }

  35. Scott Says:

    Well, I have tried to get the switch behavior to work for my forms but to no avail.
    I am using this as a test: http://www.hollyhillfl.org/radio.html
    This is the code generated from:
    http://formassembly.com/form-view.php?formID=106

    My .css files are in the root
    the .js file in folder /js

    I know I am just not seeing something simple, but thought I would ask here before I spend too much time on it.

    appreciate your comments in advance, thanks!

  36. cedsav Says:

    Scott,
    When using the jsonly.css stylesheet, the title attribute must be set. Can’t tell why, but it doesn’ work without it.

    Here the correct link to load the stylesheet.

    <link href="/css/default/wforms-jsonly.css" rel="alternate stylesheet" type="text/css" title="…something here…" />

  37. Scott Says:

    Hi cedsav. Thanks for the info. Being somewhat new to CSS and Javascript I can really do some dumb things. Like… I was trying to use your code without using it in a form. Took me a while to fiugre it out… So I am little slow… :-)
    BTW, it does work when done properly and the “title=” doesnt seem to make a difference on my end.

    Thanks again for your help!

  38. Chris Says:

    Hi there…

    I have a question regarding the swith behaviour and I was wondering if this is possible because I haven’t been able to figure it out.

    I have one checkbox as my switch and there are two tables - lets call them table 1 and table 2.

    When the the checkbox is not checked, I want table 1 to be visible and table 2 to be invisible.

    When the checkbox is checked, I want table 1 to be invisible and table 2 to be visible.

    Is this possible with your function? Could you suggest how I might be able to do this?

    Thanks in advance.
    Chris

  39. Chris Says:

    ok…I think I answered my own question.

    Obviously you put the switch on your checkbox.

    Lets say table one is just by itself - not nested within a div. Put the offstate-whateverClass as the classname. Do a css entry like table.offstate-whateverClass where table 1 is visible in the off state and invisible in the onstate.

    Table two is nested within a div. For the css you would do something like div.offstate-whateverClass where the div is invisible and the onstate is visible.

    Worked pretty good for switching visibilities of multiple items.

    If you have a better way of doing this, I would like to know how. :)

    Thanks!
    Chris

  40. cedsav Says:

    Chris, I think you have the best solution. My first idea was to put two switches on the checkbox, but I’m not sure it would work. I need to test it.
    Otherwise, you could use a radio group, like a yes/no pair with a class ’switch-a’ on the ‘yes’ and ’switch-b’ on the ‘no’… whichever works best for you.

  41. Chris Says:

    I tried the two switch on the checkbox, but it definately did not work. It only switched the first object. Was starting to get frustrated when I thought of the other solution.

    Thanks for the awesome library…keep up the good work!

  42. michelle Says:

    hi there

    your formbuilder really has saved me, it’s a wonderful tool. thanks for this!

    i have a question… i have a dropdown list with 3 entries. the first should switch to a fieldset called A for example. the second to fieldset B. these two are easy to configure. but the third entry should switch to both fieldsets A and B. is this possible to implement? i didn’t found a solution for this.

    sorry for my bad english…
    thanks in advance, michelle

  43. cedsav Says:

    Michelle, here’s how to do it:
    Your dropdown should have 3 switches
    switch-a -> will show fieldset A
    switch-b -> will show fieldset B
    switch-c -> will show both fieldsets

    Your fieldsets should have the class ‘offstate-a’ and ‘offstate-b’.
    Now, enclose both fieldsets in a div with the class ‘offstate-c’.

    <div class=”offstate-c”> <fieldset … > </fieldset > <fieldset … > </fieldset > </div>

    The trick is in the CSS:

    The div should always be visible so,

    .onstate-c, .offstate-c { display: block };

    When the switch-c is activated, wForms turns switch-a and switch-b off (because they’re in the same drop-down). Since you actually want A and B to be visible in this case, the CSS rule is:

    .onstate-c .offstate-a, .onstate-c .offstate-b { display: block !important; }

    (basically you overwrite the switch ‘off state’ when C is on)..
    I hope it’s clear.

  44. michelle Says:

    hi cedric
    thanks a lot for your answer. i have enclosed both fieldsets in a div as you have written.
    but i am not shure how i have to change the css-file, because if i just copy paste .onstate-c, .offstate-c { display: block; } in the wforms.css on line 166, there is none of the fieldsets displayed after choosing the third entry in the dropdown. can you please tell me exactly what i have to change in the wforms.css? sorry…

    thanks in advance, michelle

  45. Gilles Says:

    hi cedric

    Thanks a lot for your great work
    I have a little question :
    a question may have several sister but a question can have several mother ?

    thanks
    gilles

  46. mork Says:

    ok, I’ve got a question for you and make it a feature request if it is not currently possible :)

    I’d like to put the same switch on two checkboxes. For example, suppose that you have a list of checkboxes, and amung them are the following two which both have the switch-carType on them;
    [] I have my own car
    [] I drive my moms car sometimes

    switch-carType displays/hides a follow-up question “What is the make of the car?”

    This currently half-works. The issue is if I check both boxes the question is visible after checking the first one (good) and remains visible after checking the second one (good), but if I return and uncheck either of them, while leaving the other checked, the field becomes hidden (bad).

    Any hints/tips?

  47. cedsav Says:

    Mork.. it’s an interesting case and I’ll try to implement it in the next version of wForms. Until then, you should be able to obtain the desired result with a css trick:

    Use a ’switch-carType’ on the first checkbox and a ’switch-carWrapper’ on the second.

    Wrap your follow-up question in a div with the ‘offstate-carWrapper’ class (basicaly the first switch targets the question, the second switch targets the wrapper).

    Now your css trick:

    .onstate-carType { display: block; }
    .offstate-carWrapper .offstate-carType { display: none; }
    .onstate-carWrapper .offstate-carType { display: block; }

    That should work.

  48. Chas Says:

    Outstanding work, nothing like it! :)
    Can the switch behaviour be used to skip to next page? if so, how?

  49. cedsav Says:

    Chas, I’m not sure I understand what you mean by ’skip’ to next page.. but I think the answer is no. The switch only changes the css classes of targeted elements.

  50. Chas Says:

    Let’s say I have a checkbox on the page and it says skip this section. What i’d like to have happen is when that switch is fired the form will advance to the next page.

  51. cedsav Says:

    Chas. The switch behavior can’t do that. A custom javascript code would work though. I can post a code sample in the discussion board if you want.