header photo

via positiva

formapi

Livin' Large in Barcelona, aka FormAPI 3

The FormAPI 3 presentation went better than I expected -- I was slotted in the main room, which I wasn't expecting at all, so there were odd moments of disorientation as I manned the "panel discussion table" solo. All turned out well, though, and I think the important bits got through. I'm tinkering around with a presentaiton-sharing site to post the slides; hopefully it will work.

Also? We found a crepe bar. The crepe artiste named Elmer made us awesome crepes with things like lime chocolate, and talked smack about George W. Bush. He's from Holland and -- in case this wasn't emphasized enough -- made really awesome crepes.

Elmer makes crepes

A relatively simple overview of drupal_get_form()

A quick stab at a flowchart of the drupal_get_form() function. There are lots of subtleties that this glosses over, but it captures the overall progression.

drupal_get_form.png

Dynamic and Multi-Step With Drupal's Form API

The release of Drupal 4.7 introduced the Form API, a framework for building, displaying, validating, and processing HTML forms. With it, forms are defined as structured arrays, and those structured arrays contain all the information necessary to properly handle the form throughout its life cycle. This approach also makes it possible for modules to customize other forms (adding additional fields to a signup page, for example), and allows designers to customize the on-screen display of forms using overridable theming functions. It also makes validating form input, and avoiding form tampering, much easier. That's great!

The tradeoff of those enhancements was the loss of flexibility in certain complex scenerios -- in particular dynamic forms that change based on user input, and multi-step 'wizard' style forms. With the introduction of Form API 2.0 in version 4.8/5.0 of Drupal, though, we've eliminated the limitations that made those cases so difficult.

Dynamic Forms: Three Different Scenerios

For the purposes of this article, we'll be looking at three specific kinds of dynamic forms:

  1. The Long Form, a large form divided into multiple steps for ease of use
  2. The Wizard, a form where a user's answers in each step determine the options available in the next
  3. The Form That Builds Itself, a page where some options (clicking 'add more choices' when setting up a poll, for example) add more fields until the user chooses to submit the 'finished product.'

While the first scenerio isn't really dynamic (it simply presents different subsets of options to the user at each step along the way), all of these scenerios work by changing the form depending on the data that the user has just submitted. And that means that all three scenerios encounter the same options in the current Form API. Why is that? Read on...  Continue reading...

At long last, love for the multipart forms

UPDATE: The patch has been committed. Check out my latest post for a first draft of the docs on how to use it.

About two weeks ago I posted an epic tome explaining the current state of affairs with Drupal's form workflow, and how it affected attampts to build dynamic multi-step forms.

As we learned in that thrilling chapter of Jeff-Talks-About-Geeky-Stuff, building a form dynamically is no problem -- the tricky bit is making sure that the values from step 1 are validated and submitted with the form array from step 1, rather than the array from step 2.

Well, a lot has changed in the past two weeks. Not the least of which is the major FormAPI patch that changed things from a 'push' model to a 'pull' model. That was interesting, and had the nice side benefit of making programmatically-submitted forms a reality. Now, though, we're ready for the real multistep FormAPI meat.

A new patch has just been posted that allows Drupal to keep track of the 'which values go with which form' tangle. The details are explained in that issue, but it's the culmination of quite a bit of hacking, troubleshooting, and brainstorming by Adrian, chx, and myself. I've only been along for the ride most of the time, but it's been very exciting to see it come together.

Multi-page forms and the coders who love them.

chx and I spent some time this evening talking over the tricky connundrum of multipart (multi-step, multi-page, whatever you want to call them) forms in Drupal. Generally, they tend to fall into one of the following three categories:

  1. A really huge form divided up into multiple steps. In this scenerio you probably want to validate at each step, but need to hold onto the values (perhaps in hidden fields) until all the steps are completed and the data can be processed.
  2. A chain of forms that each complete and move on to the next. Each one should validate, submit, and hand off control to the next step, which may differ depending on the values submitted in the previous step.
  3. Forms that build themselves. You do enter values, submit, and more fields (or different) appear in the form based on what you submitted. You submit again, and again, and so on until it's "done" and then the real work of processing the form is done.

The problem is that drupal_get_form(), that workhorse of form building, validation, and processing, doesn't really lend itself to forms that are in any way dynamic. To understand why (and understand what may be a solution), we'll first revisit the current form workflow.

  1. Your function, mymodule_page(), gets called. It constructs a form array and passes it to drupal_get_form().
  2. drupal_get_form() looks to see if there is an incoming set of form values in the $_POST variable. At this point, the answer is no.
  3. drupal_get_form() skips over any validation or submission logic and just renders the $form array into HTML and spits it out.
  4. the user fills in values and clicks SUBMIT. By default, It's pointing to the same page, so your mymodule_page() function gets called again!
  5. Your mymodule_page() function builds its $form array again, and calls drupal_get_form() again.
  6. This time, though, there IS an incoming set of values in the $_POST variable. drupal_get_form() (via a helper function) takes the $form array that your mymodule_page() function passed in, and walks through it, putting the incoming values into the proper slots in the $form array.
  7. drupal_get_form() passes things on to drupal_validate_form(), which uses the passed-in $form, and the incoming $form_values, to make sure everything is kosher.
  8. If things aren't kosher, it just just spits out the rendered version of the form with the errors highlighted.
  9. If things ARE kosher, it passes things on to drupal_submit_form(), which handles actually processing the form, saving data, etc. If a 'destination' page has been specified for the form, it redirects the browser to it. If not, it renders the form.

That works smashingly well for single page forms where you enter all of your data, submit, correct any errors, then submit again. But, as we said, the hangup is in step number 6, there. See it? It's sneaky. It's using a set of submitted values from the FIRST time you built the form in step 1, but validating them against the SECOND copy of the form that you built in step 5. This works fine if it's always the same, but in cases where the form is dynamic, there will be a mismatch between the two and it will always fail validation. There are ways around it that work in certain situations, but they all tend to fall down when faced with the demanding workflow of full-sized dynamic and multipart forms.

It appears, though, that dopry's post on groups.drupal.org may be the key to the solution. What is it? That's coming soon...

Syndicate content

Miniblog

  • Totally got the third item in that list from @blakehall btw. He's the clever one! 1 hour ago
  • There are two hard problems in CompSci: optimal cache invalidation, naming things, and off-by-one errors. 2 hours ago
  • OH: "Well, the Title title can just be the title, but reign_title can't be the reign title, or the title title." 5 hours ago
  • Know Drupal? Dig wrestling? Looks like the WWE is hiring... http://j.mp/bSu4pB 2 days ago
  • I want to be the Malcolm Gladwell of Drupal APIs. My breakout book will be named 'Clear Cache.' 4 days ago

SXSW Interactive 2011!