On Form Reuse
Jan 19
In my younger developer days, I created separate Add and Edit forms for my data. I didn't know better. Then I started using Fusebox (2.0 then!) and along with it came the CF_REUSEFORM tag. For its time, this was pretty insightful: it would populate the attributes structure based on the "mode" the form was used in. There were three modes, being "new", "edit", and "validation failure". These are probably fairly self-evident but just to be sure: new means the user is entering new data; edit means they are editing existing data; and validation failure means you're redisplaying the data the user entered into a new or edit form along with some error message for them to correct. I'd say 99% of ColdFusion apps have to do something like this. More than likely, they have to do it many times.
Nowadays, I don't use the attributes scope much. I'll pass beans or transfer objects out of my model for use in my display pages and forms. But the idea is still the same. If you ever see anyone write one form for adding and one form for editing some data, the Red Flag should go up. There is no reason at all for this type of code duplication.
Say I want the user to be able to add or edit a Product. Instead of separate forms, I'll have one form. Something like this:
<form action="#mySelf##xfa.submitForm#" method="post"> Product Name: <input type="Text" value="#product.getName()#" /><br/> Product Price: <input type="Text" value="#product.getPrice()#" /><br/> <input type="Submit" value="Submit" /> </form>
So, the form is just pulling values out of a Product object. You can probably see that this will work in all of the situations we described, all we have to do is populate the values in the Product object correctly. So for a "new" form, the values might be empty strings. For "edit", they will be values already in the database, and for "validation failure", they'll be the values the user submitted in their last form submission.
Doing this means you have more reusable code. It also means you eliminate a lot of duplicate form code. In fact, if one had created separate processing logic for add vs. edit, you would eliminate that duplication too. I think reusing forms in this way is an easy way to make future maintenance easier. What do other folks, think? Do you reuse your forms in some way? Or do you still break things out into separate forms? If so, why?
Comments (4) |
del.icio.us
|
Digg It!
|
Linking Blogs
| 1892 Views


# Posted By Ben Nadel | 1/19/07 9:27 AM
I am huge fan of having the same add/edit forms. But I don't use objects, i use the FORM scope, so I am bit lost. Let's say someone submits a form and has invalid data. You show the form again with the data that they submitted. From what it seems this would require these steps:
1. Form is first hit - we must initialize.
2. Get product object (from some sort of service or something). This comes with default data of data of an existing item.
3. Display form / user enters data / form submits.
4. Get product object from database.
5. Load form data BACK into product (to update values).
6. Validate the object.
7. If valid, commit data via some .save() method or DAO or something. If not valid, re-display the form.
I just want to make sure I am understanding how you are doing it with objects.
# Posted By Brian Kotek | 1/19/07 12:35 PM
That's about it Ben. If you notice that a CFC instance is very similar to a struct like the FORM scope, you'll see the way you'd populate them is very similar. In general I pass a productID=0 to let the app know I'm dealing with a new Product. Obviously, I pass productID=10 or whatever if I'm dealing with an existing Product.
For the validation failure mode, I have the model generate an object (I call it Result) that is populated with things like isSuccess(), getErrorMessages(), etc. If isSuccess() is false (meaning it failed), the Result also has some sort of "input snapshot" (I actually call it inputSnapshot) of the data that the user had entered in the form. Lastly, I'll add a bit of conditional logic in my Controller that says "if there's a Result object present and if isSuccess() is false, populate a Product object with the values from the input snapshot". This way the form can be filled in with the data the user had entered, along with the error messages (gotten from result.getErrorMessages()).
Hope that makes it more clear? Thanks for the comment.
# Posted By Peter Bell | 1/19/07 3:36 PM
This is exactly how I handle forms. The additional benefit is that you have smart getters which allow you to put any business logic required into them. Only other thing I do is have a generic display message display at the top of the form so it can display the validation error if necessary.
If you want field level validation error display (text message next to problematic fields and different color for title of error fields, for instance) you have to put a little more logic in your bean, but I find this to be a great approach for form reuse. Note that you can also default form field values for add case just by setting default values in your business object.
# Posted By Peter Bell | 1/19/07 3:38 PM
Also, if you want to be REALLY clever, use custom data types with a HTML form decorator for the business object so you just loop over #Product.displayForm("#FieldName#")# for each fieldname and it gets the appropriate form display code for the custom data type (phone number, title, SSN, date, WYSIWYG data, etc.) and you are really DRY as you could change your WYSIWYG editor site wide just by changing the form display code for the WYSIWYG data type in one place.