The last time I blogged about this I got some great feedback, so I have gone back to it again and I am trying something new that combines some of the advice I have received from that post, and some advice from Brian Kotek.
The examples in this post use ColdBox, ColdSpring, and Transfer. I am sure that they would work just fine in other Frameworks using similar functions and techniques, so please read on.
This is an experiment. I am not touting it as a best practice. I am hoping to get feedback from the experts on this so I can improve or change where needed.
OK, now that the formalities are out of the way. Here is what I have:
This is a simple form in a ColdBox application that is used for creating calendar items with a name, start date, end date and other misc info.
And it is called via the URL:
That executes the event handler "items.edit()":
<cffunction name="edit" access="public" returntype="void" output="false">
<cfargument name="Event" type="coldbox.system.beans.requestContext" />
<!--- Get item service and an item Bean --->
<cfset var itemService = getPlugin("ioc").getBean("itemService") />
<cfset var itemBean = "" />
<cfset event.paramValue("itemid",0) />
<cfif NOT event.valueExists('itemForm')>
<cfset itemBean = itemService.getItem(event.getValue("itemid")) />
<cfset event.setCollection(itemBean.getMemento()) />
<cfset event.setLayout('Layout.Admin') />
<cfset event.setView('itemForm') />
The event handler "edit()" firsts request the itemService from the ColdSpring Factory through the BeanFactory plugin in ColdBox. It then creates an empty variable to store the itemBean.
Next, the handler params a value for "itemid" in the Event object. If an itemid is not passed in, I will assume we are creating a new item. In my service layer, I have set "0" as my indicator for this.
Next, the handler checks to see if it (the handler) was called via the form page. If it was, there will be a hidden field called itemForm. If the hidden field is NOT there, then I know that the view is being visited for the first time and I need to get data from the persistence layer. So, I call upon my service layer (itemService) to get a bean with the appropriate data based on the itemid passed in.
If it does retrieve data from the persistence layer (Which is Transfer btw), then it uses ColdBox's event.setCollection() method to add the data from Transfer's getMemento() method into the event object.
Transfer's getMemento() method gets all of the properties of a bean and puts them into a struct. ColdBox's setCollection() methods takes in a struct and adds the values to the event object's values.
Finally, my handler sets the layout and the view to display.
So now let's look at the form.
The form view itemForm.cfm looks like:
<cfform name="itemForm" action="/index.cfm?event=items.editPost" method="post">
<cfinput type="hidden" name="itemForm" value="true" />
<cfinput type="text" name="itemid" value="#event.getValue('itemid')#">
<cf_label for="itemName" required="true" label="Name">
<cfinput type="text" name="itemName" size="40" maxlength="45" value="#event.getValue('itemName')#" />
<cf_label for="startDate" required="true" label="Start Date">
<cfinput type="datefield" name="startDate" size="20" maxlength="12" value="#iif(isdate(event.getValue('endDate')), "dateFormat(event.getValue('endDate'), 'mm/dd/yyyy')", "")#" />
<cf_label for="endDate" required="false" label="End Date">
<cfinput type="datefield" name="endDate" size="20" maxlength="12" value="#iif(isdate(event.getValue('endDate')), "dateFormat(event.getValue('endDate'), 'mm/dd/yyyy')", "")#" />
<cf_label for="link" required="false" label="Link">
<cfinput type="text" name="link" size="60" maxlength="100" value="#event.getValue('link')#" />
<cf_label for="descr" required="false" label="Description">
<cftextarea name="descr" cols="50">#event.getValue('descr')#</cftextarea>
<cfinput type="submit" name="btnSubmit" value="Add/Update" class="ajaxButton" />
NOTE: Ignore the custom tag <cf_label>. It is a simple custom tag I am using for form layout
Now my form is based on the ColdBox event object. Some might argue with this, but for me, this is what feels right. The primary reason for this is because I can redisplay bad data that the end user has entered. Since the event object properties are not typed, as the bean/transferObject's are, I can leave the bad data in there. Whereas if I tried to base my view on a bean/TrO and someone put text into a numeric field, I would not be able to redisplay the text to the end user, because I would not be able to insert it into the bean/TrO.
This post is continued in part 2