Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at Scotch On The Rocks (SOTR) 2011 (Edinburgh) with:

Skin Spider : Meta Form Data And The Post Processing Url

By Ben Nadel on

To learn all about Skin Spider, click here.

To view the most updated application, click here.

To view the current code base, click here.

With the introduction of the MetaForm data structure, we gained more insight into how the form was behaving on a per-page request basis. I would like to take that structure and extend it so that we can use it to make post form-processing decisions. Previously, all "success" pages had a single option that was hard coded into the form processing code.

While this doesn't cause a problem, per say, it limits are ability to make highly useful applications. Think about addings tags to the current application: you enter the tag name, click submit, and you are taken back to the list of tags (the tag setup page). But what happens if you want to add several tags in a row? You would have to be taken back to the tag list page each time and then click on the "Add Tag" link for each tag. This just seems like extra work that isn't needed.

A better solution would be to provide the user with both an "Add Tag" and a "Save And Add Another Tag" button. The "Add Tag" button would function as it was previously (committing the data and taking the user back to the list page). The "Save And Add Another Tag" button would commit the data and then bring the user directly back to the "edit" page with a blank form (for adding a new tag). With this solution, we eliminate both the page redirection and the requirement of the user to click on the "Add Tag" link.

To accomplish this, I have extended the REQUEST.MetaForm data object to have the property, "PostProcessUrl". If you take a look at the Application.cfc ColdFusion component, in the OnRequestStart() event method, where I was initializing the "ExectionMode" property, you will see what I am talking about.

While there was one way to set the ExecutionMode property (via the FORM.metaform_exectionmode value), there are two ways to set the PostProcessUrl value. The first way is to submit, with the form, a hidden field named "metaform_postprocessurl". In this case, the value of the hidden field value would be saved into the REQUEST.MetaForm.PostProcessUrl value.

This is good, but it is a bit limiting. We don't always know what post-procssing Url we want to use until run time (ex. what button will the user press?). This scenario does not lend itself to a hidden form field too much. Of course, we can use the hidden form field, as the the system will handle it just fine, but then we would have to use JavaScript to set the field value at run time prior to form submission. This is "OK" (and is what we have to do for a dynamic ExecutionMode), but if I can get around it, I would rather not use JavaScript.

To get around the JavaScript requirement, I am taking advantage of the fact that you can give (X)HTML "Submit" buttons a name attribute. If you do this, upon form submission, both the submit button name and value will be submitted as part of the form data. Now, we don't want the post-process Url to be the value of the button (as that would then be visible to the user), so we have to make it part of the button name.

If you look at the edit_tag.cfm ColdFusion template, you will see that the "Add Another" button is named "metaform_postprocessurl_edit_tag.cfm". As you can see, the post process url "edit_tag.cfm" has been added to the "postprocessurl" submit button name. This is the "key" that will show up in the FORM scope if this button is clicked for form submission.

Now, if you look back in the Application.cfc ColdFusion component, in the OnRequestStart() event method, you will notice that after I check the FORM.metaform_postprocessurl value, I then loop over the FORM collection and check for any key that starts with "metaform_postprocessurl_". The existence of such a key would signal that a post-process-url was submitted via a submit button rather than as a hidden form field. For this reason, it takes presedence over the hidden form field, and, as you can see, overrides the REQUEST.MetaForm.PostProcessUrl (even if it was already set).

If this "dynamic" post process url key exists in the FORM field, it is deleted from the FORM scope once it has been read. Remember, these values are only used by the MetaForm object and should not be present as a general page value.

Ok, so now we have two ways to submit the request for a post-processing url, but how do we apply it. Remember, we might use it, we might not. If you take a look again at the edit_tag.cfm ColdFusion template, you will see that after the form processing is complete I am using the traditional CFLocation tag. The URL attribute of the CFLocation tag, which used to be hard coded to be "tags.cfm" now uses an IIF() / DE() combo to use the post process url first then the hard coded value second.

Now, our post process user redirection is completely dynamic. I am not crazy about the fact that I am passing the actual URL as part of the submit button name. I suspect that passing in a "command" like "REFERRER" or "NEW" would be better as we wouldn't have to worry about crazy characters. Plus, a command would remove the knowledge of the URL from the form view. Right now, the form view has to know that the edit tag page is "edit_tag.cfm". This is a point of variatoin (POV) that we should probably protect against. Once we move into a real framework, this URL will change. If we could get the button name to be abstracted out enough then we could get it to be page agnostic.

Reading over this again, I like it. I like the flexbility of the multiple methods for URL overridding. I think that I might implement a similar thing for the ExecutionMode setting. We shall see.



Reader Comments

Ben,

I noticed in your edit_tag.cfm that you are using the cgi.script_name variable to get the current page path. Just wanted to know if you have had any problems using this. I've run across situations in the past where this variable returns a blank string. Couldn't figure out way it was doing that, might have been a bug back in the 6.x series. Anywho from then on out I've always used cg.path_info. You get the same information but I've never ran across any problems like I did with cgi.script_name.

Reply to this Comment

Tony,

I have not had a problem. But, I do know that other people have commented that CGI is basically server-created so some servers will not pass along everything. In response to this information, I had found a way to get the URL not using the CGI ( http://www.bennadel.com/index.cfm?dax=blog:378.view ). Theoretically, this methodology could be used to get the "Script Name" as well as the url.

But, no, I have not had any problems to date.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.