Thursday, June 30, 2011

Togglefrog

Mostly because it's fun to think up silly names for plugins, but also thanks to experience on Stackoverflow seeing and answering lots of questions, I've been working on another jQuery plugin.

The Togglefrog plugin attempts to handle the (usually) simple problem of forms with sometimes-relevant, sometimes-not sections. Consider a reservation or booking form for a service that allows for some number of discounts based on organizational affiliations. Each separate type of affiliation might call for different messaging, authentication inputs, and even further choices. In the form, radio buttons or checkboxes select between options, and it's nice to make it clear that some parts of the form are only interesting in certain situations.

For a simpler, goofy example, consider a lunch menu with "Vegan", "Vegetarian", and "Omnivore" sections. To clarify the separation between them, the user is asked which general menu they're interested in, and then the form will show the separate choices of that type.

Vegan Vegetarian Omnivore
Below those would be the choices, but ideally we'd like for only the right choices to show up; we don't want vegans to panic at being offered a steak.

What Togglefrog does is allow the markup itself to indicate how the conditional sections of the form — either individual elements or sections grouped by container elements — to indicate that they're to be controlled by a toggler. A toggler can be a radio button, a checkbox, or an option in a <select> element.

To do that, the sections of the form (and note that really forms have nothing directly to do with this, it's just part of this example) is given one or more "data-" attributes: <div style='padding: 10px 0px 10px 5px'> <input type='radio' name='diet' id='vegan' value='vegan'> Vegan <input type='radio' name='diet' id='veggie' value='veggie'> Vegetarian <input type='radio' name='diet' id='omni' value='omni'> Omnivore </div> <div class='togglefrog menu' data-toggler='vegan'> <input type='radio' name='meal' value='sprouts'> Sprout salad with chickpea chips<br> <input type='radio' name='meal' value='tofu'> Toasted pressed tofu with soy-garlic gravy with sweet/sour green beans<br> <input type='radio' name='meal' value='beanburger'> Black bean burger on spelt-quinoa bun with homemade ketchup and sweet potato fries </div> <div class='togglefrog menu' data-toggler='veggie'> <input type='radio' name='meal' value='grill'> Grilled cheddar with tomato on spelt-quinoa bread with sweet potato fries<br> <input type='radio' name='meal' value='taco'> Seitan and pepper stir-fry and aged Monterrey Jack in whole-wheat tortillas with tomato-parsley salad<br> <input type='radio' name='meal' value='soup'> Creamy broccoli cheddar soup with pumpkin seed crackers </div> <div class='togglefrog menu' data-toggler='omni'> <input type='radio' name='meal' value='meatburger'> Angus beef burger on spelt-quinoa bun with homemade ketchup and sweet potato fries<br> <input type='radio' name='meal' value='salmon'> Alaskan salmon steak with chipotle glaze and aromatic brown rice<br> <input type='radio' name='meal' value='chicken'> Chardonnay-poached chicken breast with buttered peas and aromatic brown rice </div> First you see the markup for the three radio buttons, then the form sections. The "data-toggler" attributes give the "id" values the plugin looks for to find the togglers.

If that markup were put on a page that imported jQuery and Togglefrog, and the <body> tag also had class "togglefrog", then there's not even any code to write. The plugin wires up everything marked with that class (except the body element, of course) guided by the "data-" attributes. Oh, and we'll need some CSS too: div.menu { position: absolute; display: none; } div.menu.toggled { display: block; } The "toggled" class will be added by the plugin to each toggled element when its toggler is "on" (checked for a checkbox or radio button, and selected for an option). You can see this particular example in action at this jsfiddle page. Go there now and play with it. Note that initially, none of the menu types are selected; normally I don't like that, but it's helpful with this example. As soon as you click a menu button, you'll see the corresponding items show up.

You may be saying, "Gee, big deal - a whole plugin just for something as simple as that?" Well, two points. First, if you're working with a web application that's got lots of this stuff, it's tedious and error-prone to re-code the same stuff over and over again for every particular form. Besides, the plugin isn't that big.

The second point is that it's not really so simple. Note that the menu item radio buttons for the different meals are all named "meal". That way, the back-end form handler only has to worry about one parameter — "meal". The plugin makes sure that any toggled section that's toggled "off" (that is, its toggler radio button is unchecked) then all the inputs are marked as disabled. The only ones that'll be submitted will be those corresponding to the menu choice.

Note also that if you click "Vegan" and select something, then click "Omnivore" and select one of those, and then go back to "Vegan", your original choice is preserved. The plugin handles the juggling of those radio buttons so that the currently-visible members of a like-named group keep any former selection they may have had.

In addition to just hiding/revealing form sections, the plugin can be used to do other sorts of style changes. For example, it's pretty easy to implement your own "fancy" checkbox mechanism with it. You'd do something like this:

  • Put a checkbox on the page and make it hidden. (You can't just make it "display: none" because then it won't work in IE; make it transparent or position it way off to the left of the page.)
  • Create a <label> element and style it with a sprite background for your fancy checkbox (or radio button or whatever). Make the label be toggled by the checkbox, and also "for" the checkbox.
  • In your CSS, use the "toggled" class (which you can override by the way) to move the sprite between the untoggled and toggled states.

The plugin is available from github with a short README and a minimal test file. I'll write up a real documentation page at some point. I also need a cute frog logo.