We've seen how to convert data list and data detail pages from procedural code to Mach-II events. Now we need to refactor how we build form and action pages.
Create a Company
From a data list page, we generally have the options to Add a New Item, View Item Deatils or Edit Item.
Clicking on "Add a Company", we get a new Company form.
Here's the procedural version of this page:
The link to "Add a new Company" passes COMPANY_ID=0 in the querystring, so the query qCompanies returns an emtpy record set, so the form fields are all populated with empty strings.
We've already refactored the layout HTML into Mach-II <page-view>s. All that's left are three major sections of code:
The query qCompanies.
Javascript to validate the form's contents.
The form itself.
Creating the showCompanyForm event
First we need a query that returns a single company record. We already have this code in the CompanyListener, which uses the Company bean and CompanyDAO.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <notify listener="CompanyListener" method="getCompanyDetail" resultArg="companyBean" />1<notify listener="CompanyListener" method="getCompanyDetail" resultArg="companyBean" />
Next we need to move the Company form and Javascript to its own CFM file.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <page-view name="companyForm" page="/views/companies/05/company_form.cfm" />1<page-view name="companyForm" page="/views/companies/05/company_form.cfm" />
The values of the form fields are now being populated by the contents of the Company bean.
Optionally, we can move the Javascript to an external file.
If we use an external JS file, then we need to reference it in company_form.cfm.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <cfif event.getArge("jsFile") is not ""> <script src="#event.getArge("jsFile")#" type="text/javascript"></script> </cfif>1<cfif event.getArge("jsFile") is not ""> 2<script src="#event.getArge("jsFile")#" type="text/javascript"></script> 3</cfif>
The event-handler for showCompanyForm
Filtering data
The showCompanyForm event will be starting point for Creating, Updating and Deleting Company records.
The form is setup to show different submit actions based on url.COMPANY_ID.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <cfif company.getCompanyID() eq 0> <input type="submit" name="addCompany" value="Add Company" /> <cfelse> <input type="submit" name="editCompany" value="Edit Company" /> <input type="submit" name="deleteCompany" value="Delete Company" /> </cfif>1<cfif company.getCompanyID() eq 0> 2<input type="submit" name="addCompany" value="Add Company" /> 3<cfelse> 4<input type="submit" name="editCompany" value="Edit Company" /> 5<input type="submit" name="deleteCompany" value="Delete Company" /> 6</cfif>
When you have multiple submit buttons in a form, whichever one you click will be the name/value pair that exists on the action page. (This is basic HTML functionality.)
Procedural version
In the procedural version, the form submits to a processing page.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <form name="companyData" action="company_form_process.cfm" method="post" onSubmit="return validateCompany()">1<form name="companyData" action="company_form_process.cfm" method="post" onSubmit="return validateCompany()">
A different query is run based on which submit button was used to submit the form.
Mach-II version
Now we're going to submit the form to an event instead of a page.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <form name="companyData" action="index.cfm?event=processCompanyData" method="post" onSubmit="return validateCompany()">1<form name="companyData" action="index.cfm?event=processCompanyData" method="post" onSubmit="return validateCompany()">
What is a Mach-II Event Filter?
Definition
An event filter is an object (component/CFC) that allows you to run some logic, then return true or false based on the results. Any filter that you create extends MachII.framework.EventFilter.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <cfcomponent displayname="FilterCompanyAction" output="no" extends="MachII.framework.EventFilter" hint="Processes Company data based on the Submit button clicked.">1<cfcomponent displayname="FilterCompanyAction" output="no" extends="MachII.framework.EventFilter" hint="Processes Company data based on the Submit button clicked.">
The required function filterEvent takes 3 arguments.
You can optionally create a configure() method to handle anything that needs to run when the Filter is created. This works the same as a Listerner's configure() method.
All Filters are created when the application loads for the first time. They are placed into the application scope, so be aware of your variable scopes.
Usage
When a filter returns true, then Mach-II continues processing the event-handler. In the event-handler processCompanyData, if the filter FilterCompanyAction returns true, then the announce command is run and we proceed to the "home" event.
When a filter returns false, Mach-II stops processing the rest of the current event-handler and goes to the next one. Usually you'll announce the next event before returning false.
In the above code, if the "addCompany" submit button was clicked, then event.getArg("addCompany") will not be an empty string, so the Filter then announces the event processCompanyCreate and copies all of the current event Args to that event. Then it returns false, telling Mach-II to stop processing the current event-handler (processCompanyData).
So far, we have replaced part of the functionlity of the procedural file "company_form_process.cfm". Now we just need to handle the database interactions.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <event-handler event="processCompanyData" access="public"> <filter name="FilterCompanyAction"/> <announce event="home" /> </event-handler>1<event-handler event="processCompanyData" access="public"> 2<filter name="FilterCompanyAction"/> 3<announce event="home" /> 4</event-handler>
Based on the action (button) we chose in showCompanyForm, the filter FilterCompanyAction then announces the next event.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <event-handler event="processCompanyCreate" access="private"> <notify listener="CompanyListener" method="createCompany" /> <announce event="showCompanies" /> </event-handler>1<event-handler event="processCompanyCreate" access="private"> 2<notify listener="CompanyListener" method="createCompany" /> 3<announce event="showCompanies" /> 4</event-handler>
The event processCompanyCreate notifies the Listener CompanyListener to call the method createCompany.
The method createCompany creates an instance of the CompanyDAO, then creates and populates an instance of the Company bean with the form data and finally passes the Company bean to the create() method of the DAO.
Once all of this has processed, the event showCompanies is loaded.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <event-handler event="processCompanyUpdate" access="private"> <notify listener="CompanyListener" method="updateCompany" /> <announce event="showCompanies" /> </event-handler>1<event-handler event="processCompanyUpdate" access="private"> 2<notify listener="CompanyListener" method="updateCompany" /> 3<announce event="showCompanies" /> 4</event-handler>
The event processCompanyUpdate notifies the Listener CompanyListener to call the method updateCompany.
The method updateCompany creates an instance of the CompanyDAO, then creates and populates an instance of the Company bean with the form data and finally passes the Company bean to the update() method of the DAO.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <cffunction name="updateCompany" access="public" output="false" returntype="boolean" hint="Updates a Company record.">
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <event-handler event="processCompanyDelete" access="private"> <notify listener="CompanyListener" method="deleteCompany" /> <announce event="showCompanies" /> </event-handler>1<event-handler event="processCompanyDelete" access="private"> 2<notify listener="CompanyListener" method="deleteCompany" /> 3<announce event="showCompanies" /> 4</event-handler>
The event processCompanyDelete notifies the Listener CompanyListener to call the method deleteCompany.
The method deleteCompany creates an instance of the CompanyDAO, then creates and populates an instance of the Company bean with the COMPANY_ID only and finally passes the Company bean to the delete() method of the DAO.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <cffunction name="deleteCompany" access="public" output="false" returntype="boolean" hint="Updates a Company record.">
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org <cffunction name="delete" access="public" returntype="boolean" output="false" hint="Updates a Company record."> <cfargument name="company" type="Company" required="true" hint="Company bean" /> <cfset var qDelCompany = "" /> <cftransaction> <cftry> <cfquery name="qDelCompany" datasource="#variables.DSN#"> DELETE FROM CF_COMPANIES WHERE COMPANY_ID = <cfqueryparam value="#arguments.company.getCompanyID()#" cfsqltype="cf_sql_integer" /> </cfquery> <cfcatch type="database"> <cftransaction action="rollback" /> <cfreturn false /> </cfcatch> </cftry> </cftransaction>
Once all of this has processed, the event showCompanies is loaded.
Ack! Carpel Tunnel!
Yes, that's a heck of a lot of code for such a small application. If this was a real world app, I'm sure I'd just create it the procedural way. However, the concepts and techniques shown so far are the building blocks used in many high traffic and mission critical applications.
You can see these changes in action by using the version 5 files.
Rename the version 4 mach-ii.xml file to mach-ii.04.xml
Rename mach-ii.05.xml to mach-ii.xml
Reload the application and click the Companies link in the left-hand navigation.
Next chapter
The Mach-II Primer has now caught up with the Object Oriented ColdFusion Primer. I'm working on a post for that primer which will cover a Complex DAO (working with multiple tables or data sources). After that, I'll get into the Service Object and Object Factory. Once those are done, I'll come back to the Mach-II Primer to show how to implement those objects in the sample application.
But before then: We've been converting this application to an MVC framework in an effort to reduce the amount of redundant code. You should have noticed by now that there are a lot of the same objects being created in the Listeners. They're being created every time a function is called. That's redundant code too.
Next time we'll use a Plug-in or a new feature of Mach-II 1.5 to turn some objects into Mach-II Properties.
Check All Checkboxes with JQuery
Rafael said: Hey Guys,
I'm trying to accomplish the following using jqCheckAll3():
If a checkbox is checked it...
[More]
Check All Checkboxes with JQuery
Ben said: Thanks for this, and big thanks to Tom for saving me sooo much time figuring out why all my checkbox...
[More]
iKnowKungFoo is Evolving
Seth Johnson said: Welcome back! We had some great discussions about the real estate industry at Max. I would be inter...
[More]