Persisting Values in ColdBox
I have never found a way to validate data I feel is 100% right for me, but I think I am getting close, let me explain.
I have a simple ColdBox 'view' containing my user form. This form is used to both create and update user's credentials.
2
3 <cfoutput>
4 <fieldset>
5 <div class="fm-req">
6 <label for="firstname">First Name</label>
7 <input id="firstname" name="firstname" type="text" class="text" value="#rc.bean.getfirstname()#" maxlength="15">
8 </div>
9 <div class="fm-req">
10 <label for="surname">Last Name</label>
11 <input id="surname" name="surname" type="text" class="text" maxlength="15" value="#rc.bean.getsurname()#">
12 </div>
13 <div class="fm-req">
14 <label for="email">Email Address</label>
15 <input id="email" name="email" type="text" class="text" maxlength="100" value="#rc.bean.getemail()#">
16 </div>
17 <div class="fm-req">
18 <label for="username">Username</label>
19 <input id="username" name="username" type="text" class="text" maxlength="12" value="#rc.bean.getusername()#">
20 </div>
21 <div class="fm-req">
22 <label for="password">Password</label>
23 <input id="password" name="password" type="password" class="text" maxlength="20" value="#variables.PasswordEncrypt#">
24 </div>
25 </fieldset>
26 </cfoutput>
2
3 <!--- Edit User --->
4 <cffunction name="editUser" access="public" returntype="void" output="false">
5 <cfargument name="Event" type="coldbox.system.beans.requestContext">
6 <cfscript>
7 var rc = event.getCollection();// RC Reference
8 var userBean = variables.adminUsersService.createAdminUserBean(); //Create adminUserBean
9 getPlugin('beanFactory').populateBean(userBean);//the magic bean machine
10 variables.adminUsersService.getUserByID(userBean);
11 rc.bean = userBean;
12 event.setValue("pageTitle","Edit System User");//Form H1 Title
13 event.setValue("formURL","/users/updateUser?adminId=#rc.adminId#");
14 event.setValue("buttonValue1","Update User");//H1 Title
15 runEvent(event='users.createUserTabs',private=true); // Create User Tabs
16 Event.setView("user/edit"); // Set the View To Display, after Logic
17 </cfscript>
18 </cffunction>
I use one handler to create a new user and another to update, the only difference is the update handler pre populates the object from the database. So far simple stuff. Next I needed to validate my input. Again simple, I would submit to an intermediate handler that would validate my data against the object. However my dilemma is what to do if validation fails!
2 <cffunction name="validation" access="public" returntype="void" output="false">
3 <cfargument name="Event" type="coldbox.system.beans.requestContext">
4 <cfscript>
5 var rc = event.getCollection();// RC Reference
6 var userBean = variables.adminUsersService.createAdminUserBean(); //Create adminUserBean
7 getPlugin('beanFactory').populateBean(userBean);//the magic bean machine
8
9 errors = userBean.validateUserALL();//Check For Validation Errors
10
11 if NOTT ArrayLen(errors)){//No Validation Errors
12
13 if ( variables.adminUsersService.updateUser(userBean)) {//Update Was OK
14 getPlugin("messagebox").setMessage("info", "User was successfully updated.");
15 }
16 else {//Could Not Update User Show Error Message
17 getPlugin("messagebox").setMessage("error", "Sorry, for some reason this user was not updated!");
18 }
19
20 setNextEvent('users.overView'); // Set the Event To Run, After Logic
21 }//End Of No Validation Errors
22
23 else {//We Have Validation Errors Show The User A Message
24 getPlugin("messagebox").setMessage("error", "<b>The Following Validation Errors Occurred:</b><br />",errors);
25
26 ///what to do here?
27
28 }
29 </cfscript>
30 </cffunction>
Option 1: Do I include the 'view' again within the validation handler so the object data would persist?
Option 2: Do I take them back to the original handler that made the post?
Now option 2 would mean my objects data would not persist, it would either be repopulated by the update handler or cleared by the create handler!
However I favour option 2 because by going back to the original handler you don't see in the URL the name of the validation handler as it only an intermediate stage.
So how do you persist the entire object so the user does not lose the data they have posted?
Well ColdBox has an internal flash memory that you can use in order to persist variables across requests without sending them via the URL. – direct quote. I could do the following I guess...
2 getPlugin("messagebox").setMessage("error", "<b>The Following Validation Errors Occurred:</b><br />",errors);
3 myStruct = {FIRSTNAME=userBean.getFIRSTNAME()}; //etc.....
4 persistVariables(varStruct=myStruct);
5 setNextEvent(event='users.newUser');

However this gets cumbersome and I have to add variable or create a strut.
So Far I have not found a method which is easier have you?




setNextEvent
event="myEvent",persist="list,of,variables,in,request,collection
http://forums.coldbox.org/index.cfm?event=ehMessag...
"Why would I want to perisist the value I'm submitting with the form, you ask?"
glad its was answered and not just me! after fully testing my code I did have a few issues. version 3 looks like its going to address a lot. thanks for the post.
does anyone else do this another way, if validation fails what do you do?
The problem you have with that method is you would have to maintain your validation in both the update, create or anything other systems you use. where if you just had one validation handler like in my example this would not be the case. When an application gets large I really appreciate the extra work and for me its worth the effort.
If its ADD, then use blank fields, if it is edit then pre-populate, if it is delete just display non editable data.
You can then use a CFC for both cleint and server side validation, just call it via AJAX to do the client side. There is a nice cfc on riaforge that does it all for you now.
Populate Bean:
<cfset getPlugin("beanFactory").populateBean(rc.user)>
<cfset rc.user.setUserType(userType)>
<cfset rc.user.setUpdatedOn(now())>
Validate Password
<cfif newPassword neq "" and newPassword eq confirmPassword>
<cfset rc.user.setPassword(newPassword)>
<cfelseif newPassword neq "" and newPassword neq confirmPassword>
<cfset getPlugin("messagebox").setMessage("error", "Validation error: Passwords are not equal")>
<cfset isValidationError = 1>
</cfif>
<!--- Validation Error? --->
<cfif isValidationError>
<cfset dspEditUser(Event)>
<cfelse>
<cfset getPlugin("ioc").getBean("UserManager").saveUser(rc.user)>
<cfset setNextEvent("admin.ehUser.dspUsers")>
</cfif>
If a validation error occurs the message plugin is run and then <cfset dspEditUser(Event)> will run the dspEditUser handler again but now populated with the form fields that are correct and the password field empty and a message box at the top.
In my dspeditUser I only have:
<cffunction name="dspEditUser" access="public" returntype="void" output="false">
<cfargument name="Event" type="coldbox.system.beans.requestContext">
<cfset var rc = Event.getCollection() />
<cfif not isDefined("rc.user")>
<cfset rc.user = getPlugin("ioc").getBean("UserManager").getUser( Event.getValue("userId","") ) />
</cfif>
<cfset rc.userTypes = getPlugin("ioc").getBean("UserManager").getUserTypes()>
<!--- EXIT EVENT HANDLERS: --->
<cfset rc.xehSave = "admin.ehUser.doSaveUser">
<cfset rc.xehBack = "admin.ehUser.dspUsers">
<cfset Event.setView("user/edit")>
</cffunction>
I use dspEditUser both for new users and to edit users. If there is no user bean in the RC a new one is created and if one exist the form field is populated from the bean. This way I only need three handlers and views for CRUD operations and does not need to persist any data. I use Transfer and LightWire to glue it togheter. I know that it´s getting way more complicated if you do for example a wizard where a user will be able to navigate back and forth or you include a JQuery/AJAX functionality in your forms. I have based my cfoo learning and developement on Ernst van der Linden´s excellent examples.