I remember back in 1999 when I first started using Fusebox. The idea of taking all form and URL variables and keeping them in the attributes scope was brilliant. Now, all of the frameworks do something similar to wrap up the incoming variables, usually into an event object with event arguments.

However, one thing has always bugged me, and that is the "all or nothing" way that this is done. Many are the times I've had to pass the entire event arguments structure into a CFC just to get at a subset of them, perhaps the ones in the edit form for a User. I may want to use just the form fields for the User to populate a Bean or a Transfer Object. But getting at just those values can be difficult or somewhat kludgy, like passing in the whole struct as an argument collection and then relying on cfargument tags on the other side to actually whittle it down.

To help with this, I've created a CFC that will let you implicitly create arbitrary arrays and structures based on the names of your form fields. For example, this form:

<input name="user.id" type="text" value="user"><br />
<input name="user.name" type="text" value="user"><br />
<input name="user.password" type="text" value="user"><br />
		

Would be parsed and turned into this on the server:

Here are more examples to demonstrate the ability to do this as far as you need to go. Create arrays or structures within a structure, as well as a list of values if the fields have the same name (such as checkboxes):

<input name="user2.id" type="text" value="user2"><br />
<input name="user2.name" type="text" value="user2"><br />
<input name="user2.password" type="text" value="user2"><br />
<input name="user2.permission[2]" type="text" value="user2.permission[2]"><br />
<input name="user2.permission[1]" type="text" value="user2.permission[1]"><br />
<input name="user2.category.11" type="text" value="user2"><br />
<input name="user2.category.8" type="text" value="user2"><br />
<input name="user2.userType" type="text" value="user2type1"><br />
<input name="user2.userType" type="text" value="user2type2"><br />
		

Create an array of structures, that each contain their own arrays and structures. This can be handy for dynamic forms where you don't know how many sets of data will be on the page:

<input name="employee[1].name" type="text" value="employee[1]"><br />
<input name="employee[1].phone" type="text" value="employee[1]"><br />
<input name="employee[1].permission.2" type="text" value="employee[1].permission.2"><br />
<input name="employee[1].permission.1" type="text" value="employee[1].permission.1"><br />
<input name="employee[1].mode[2]" type="text" value="employee[1].mode[2]"><br />
<input name="employee[1].mode[1]" type="text" value="employee[1].mode[1]"><br />

<input name="employee[2].name" type="text" value="employee[2]"><br />
<input name="employee[2].phone" type="text" value="employee[2]"><br />
<input name="employee[2].permission.2" type="text" value="employee[2].permission.2"><br />
<input name="employee[2].permission.1" type="text" value="employee[2].permission.1"><br />
<input name="employee[2].mode[1]" type="text" value="employee[2]mode[1]"><br />
<input name="employee[2].mode[2]" type="text" value="employee[2]mode[2]"><br />
		

And lastly, a demonstration that the structure can be arbitrary if you had some need for it to be:

<input name="company[1].name.firstName.prefix" type="text" value="company[1]"><br />
<input name="company[1].phone[2].something[5]" type="text" value="company[1]"><br />
		

I'm considering cleaning this up and putting it up on RIAForge as a Form Utility CFC. Personally, I think it would be great just to pass in the User structure and know that all it has is the user-related form fields and nothing more. What do folks think? Would you use this as an alternative to passing in a whole event structure?

Comments Comments (24) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 10958 Views

Comments

  • # Posted By user | 9/4/07 11:17 AM

    Wow, its just like PHP! /smirk

  • # Posted By Brian Kotek | 9/4/07 11:20 AM

    Wow, it's almost a useful comment!

    By the way, PHP won't create arbitrarily nested arrays and, more importantly, key-value pairs like this. Nice try though!

  • # Posted By tony petruzzi | 9/4/07 11:40 AM

    This is f**king brilliant. Do you know how many times I've name a field user_name so I could loop through the form structure and parse out the fields I want! Great find Brian!!!!

  • # Posted By Adam Fortuna | 9/4/07 1:00 PM

    Very cool Brian, something from Rails that's easily translatable to any coldfusion framework. Just a side note, ColdFusion on Wheels has this built in, although I think the form naming convention is a little different -- and it's only for top level structures and not arrays (last time i checked that is, could be different now). This really keeps the code in the controllers clean, and if your service layer is taking structures then they might even be down to one line in some cases!

  • # Posted By Brian Kotek | 9/4/07 1:19 PM

    @Tony: thanks!

    @Adam: yep, that's the whole idea. Automatically creating a top-level struct is nice, but I wanted the ability to do anything since there's no telling how you want to group your fields.

  • # Posted By Matt Williams | 9/4/07 2:33 PM

    To show my lack of js knowledge, I'll ask this..

    Does the input naming affect javascript referencing in things like qForms? I'm assuming not if this type of thing is popular in rails already.

    For example, this input...
    <input name="employee[2].mode[2]" id="employee[2].mode[2]" type="text" value="employee[2]mode[2]"><br />

    can be referenced as so...? document.getElementById('employee[2].mode[2]').value

  • # Posted By Brian Kotek | 9/4/07 2:38 PM

    Hmm, fair question Matt and I'm honestly not sure of the answer. I agree, I think it should still work since you're referencing the name of the field as a string, so I wouldn't think JavaScript would know or care what the actual field name is. But when I have a chance I will see if I can test that.

  • # Posted By Brian Kotek | 9/4/07 2:47 PM

    Seems to work fine. Note that using getElementById uses the ID, not the element name. But the same thing applies. So either of these work:

    alert(document.forms['testform'].elements['company[1].name.firstName.prefix'].value);
    alert(document.getElementById('company[1].name.firstName.prefix').value);

  • # Posted By Matt Williams | 9/4/07 3:04 PM

    Cool beans, so to speak.

    I like this approach better than Mach-II's event-bean deal as I felt like I wasn't keeping my M, V and C well separated when using that.

    By the way, the last captcha characters were 'mat'. That was pretty slick.

  • # Posted By Joe Rinehart | 9/4/07 3:48 PM

    Ok, that's just fantastic. It'll be in the the next MG :)

  • # Posted By Chris Dawes | 9/4/07 10:10 PM

    Can someone confirm this works across the various in-use versions of minor browsers (opera, safari) One would assume is should, but with those two browsers you never know.

  • # Posted By Brian Kotek | 9/4/07 10:27 PM

    All the processing happens on the server, so the browser shouldn't make any difference.

  • # Posted By Chris Dawes | 9/5/07 6:21 AM

    Duh... I'm not asking about the server side. Some browsers have in the past sent parameters such as you are displaying in interesting ways or not at all. One browser that you can't count on for standards is IE for pocket pc, the other is safari up to the latest version and opera before version 5. If you have been around the internet for a few years you would be familiar with some of the issue we've had with these kind of techniques in the past.

    Although these days with double bite characters in play this should not be a problem, however I'd check it out before people implement it in a mainstream app.

  • # Posted By Brian Kotek | 9/5/07 10:44 AM

    Fair enough. I'll leave it to the users of those browsers to determine whether this will work for them. Some Google searches would probably reveal the answer, since what's really being described is a browser that won't allow dots or brackets in any form field names.

    I sort of take the "Gmail approach", and my view would be that if someone is using a browser that is that old or quirky, I really don't care if they can use my app or not.

  • # Posted By Peter Bell | 9/5/07 10:45 AM

    This is really great. I hacked together something similar but it only handled a single . - this would be MUCH more useful - especially for arrays where you're editing multiple records. Please comment below when you post this or even just throw up an enclosure with the "ugly" version - can't wait to give this a try :)

  • # Posted By Brian Kotek | 9/5/07 11:29 AM

    Will do Peter! I'll post it today or tomorrow as a download here. If no one finds anything terribly wrong, I'll create an RIAForge project for it. I'll reply to this post and also post a new one to let folks know it is ready.

  • # Posted By Tony Petruzzi | 9/5/07 9:30 PM

    Brian,

    Post the code!!!! I'm itching to start using this in an application I'm building right now. I'll beta test for you.

  • # Posted By Brian Kotek | 9/5/07 9:42 PM

    OK it's in the sidebar! Enjoy! And let me know if you run into any problems.

  • # Posted By Gerald Guido | 8/15/08 3:50 PM

    Brian,

    Freakin Awesome! I see what you meant on you preso. Why aren't more ppl using this? I was just trying to assemble the contents of a dynamic form into a struct and remembered your cfc. Presto. Problem solved.

  • # Posted By John Farrar | 9/5/08 10:38 AM

    OK... it seems to me that using CSS selectors in AJAX libraries like jQuery this is going to fail. I am wondering if we can come up with a solution for this. The following in jQuery sees the dotted items as classes. It was a bit shocking to me that no one has either brought this up as an issue or said that they found it to work.
    $("p.myClass").css("border","3px solid red");

  • # Posted By John Farrar | 9/12/08 5:47 PM

    I figured out how to resolve this outside the component. :) AJAX works with my solution to resolve the 'issue' (since the word bug used elsewhere was debated... we will say I can make it work and leave it at that.) We are building it into SOS for beta release 2. :) Good work.

  • # Posted By Byron Raines | 11/12/08 3:21 PM

    Brian,

    I'm testing out your FormUltilities cfc. So far so good. I am getting one error that I've worked around. I'm using MG3. I have the FormUtilities.cfc in the "helper" directory.

    Inside my controller cfc if have:

    <cfset helpers.FormUtilities.buildFormCollections(form) />

    When I run it, I get the following:

    Message    Element INSTANCE.UPDATEFORMSCOPE is undefined in VARIABLES.
    Detail    
    Extended Info    
    Tag Context    D:\Inetpub\wwwroot\Admin\helpers\FormUtilities.cfc (57)

    If I hard code a value of "true" in the "buildFormCollections" function, it works as expected. It like the "init" function is not running.

    Any ideas?

    Thanks

    byron

  • # Posted By Byron Raines | 11/12/08 3:30 PM

    As a followup, I put the FormUtilities in the webroot, then created a bean in Coldspring for it.

    <bean id="FormUtilities" class="FormUtilities.FormUtilities" />

    then used:

    <cfset beans.FormUtilities.buildFormCollections(form) />

    Worked fine. My assumption is that when using this method, the "init" gets fired off, where as my original method, it does not. If this is the case, how do I make sure the "init" is fired off when using "helpers" feature of MG3? (Should I post this to MG3 group)?

    Thanks

    Byron

  • # Posted By Brian Kotek | 11/12/08 4:43 PM

    Yeah sounds like it may be a MG3 thing? I hesitate to say "bug" since I'm not exactly sure what the problem is. It can't hurt to post it to the list.