In a non-frameworked application of course you can still do the same thing, and we've done it in ColdFusion for years either using includes or custom tags. That code would look something like this:
dashboard.cfm
<div><cfinclude template="searchform.cfm"></div> <div style="float:left"> <cfmodule template="report_a.cfm"> </div> <div style="float:left"> <cfmodule template="report_b.cfm"> </div>
While this works, what you end up with is CFQUERY tags or possibly business logic in those custom tags and/or includes. That's okay, but we want to separate the business logic from the view so we can reuse more of our code, which is what our events are designed to accomplish. So frameworks typically will provide a way to get this same effect by executing additional events and I call these "nested" or "chained". The only difference between the two is that while a "nested" event is executed immediately, a "chained" event is only "announced" to the framework which then defers it to execute at a later time after the current event has finished executing.
ColdBox: The framework offers nested events via the runEvent method typically used within the event-handler CFC. The dashboard might look like this:
<cfcomponent extends="coldbox.system.eventhandler">
<cffunction name="dashboard" access="public" returntype="void" output="false">
<cfargument name="Event" type="coldbox.system.beans.requestContext" />
<cfset var rc = Event.getCollection() />
<cfsavecontent variable="rc.form">
<cfset runEvent("[handler].searchform") />
</cfsavecontent>
<cfsavecontent variable="rc.report_a">
<cfset runEvent("[handler].reportA") />
</cfsavecontent>
<cfsavecontent variable="rc.report_b">
<cfset runEvent("[handler].reportB") />
</cfsavecontent>
<cfset Event.setView("dashboard") />
</cffunction>
</cfcomponent>
Fusebox (traditional): The framework offers nested events via the <do> XML node (Fusebox calls these "verbs"). The dashboard might look like this:
<circuit access="public"> <fuseaction name="dashboard"> <do action="[circuit].searchform" contentvariable="searchform" /> <do action="[circuit].reportA" contentvariable="report_a" /> <do action="[circuit].reportB" contentvariable="report_b" /> <do action="display.dashboard" /> </cffunction> </cfcomponent>
Fusebox (implicit): With fusebox all the features procided by the built-in XML syntax are mirrored in the framework's CFC architecture.
<cfcomponent output="false"> <cffunction name="index" access="public"> <cfargument name="myFusebox" /> <cfargument name="event" /> <cfscript> myFusebox.do(action"[circuit].searchform" contentvariable="searchform"); myFusebox.do(action="[circuit].reportA" contentvariable="report_a"); myFusebox.do action="[circuit].reportB" contentvariable="report_b"); myFusebox.do action="display.dashboard"); </cfscript> </cffunction> </cfcomponent>
Mach-II: Until recently Mach-II didn't offer any kind of in-line support for event-execution... Actually it still doesn't. Mach-II offers an <announce> tag in its XML configuration which allows events to be chained together. However in 1.5 Mach-II added "subroutines" which are segments of code very similar to events that can be reused in-line within an event. A traditional fusebox application wouldn't use an event announcement to call the events for the search form and reports in this example. So you might actually prefer subroutines for something like this, allowing you to use the same subroutines in both the dashboard and in other events dedicated to the individual reports.
<!DOCTYPE mach-ii PUBLIC "-//Mach-II//DTD Mach-II Configuration 1.5.0//EN" "http://www.mach-ii.com/dtds/mach-ii_1_5_0.dtd"> <mach-ii version="1.5"> <listeners> <listener name="reportMan" type="mii.listeners.reportMan" /> </listeners> <event-handlers> <event-handler event="dashboard"> <view-page name="searchform" contentArg="searchform" /> <execute subroutine="reportA" /> <execute subroutine="reportB" /> <view-page name="dashboard" /> </event-handler> ... <event-handlers> <page-views> <page-view name="searchform" page="mii/views/searchform.cfm" /> <page-view name="reportA" page="mii/views/reportA.cfm" /> <page-view name="reportB" page="mii/views/reportB.cfm" /> <page-view name="dashboard" page="mii/views/dashboard.cfm" /> </page-views> <subroutines> <subroutine name="reportA"> <notify listener="reportMan" method="getReportA" resultArg="qReport" /> <view-page name="reportA" contentArg="report_a" /> </subroutine> <subroutine name="reportB"> <notify listener="reportMan" method="getReportB" resultArg="qReport" /> <view-page name="reportA" contentArg="report_b" /> </subroutine> </subroutines> </cfcomponent>
Model-Glue: The latest version of Model-Glue as far as I can tell doesn't offer any kind of nested events, although it does offer event-chaning via the <result> XML tag. An example of the above in Model-Glue might look like this:
<modelglue> <controllers> <controller name="reportMan" type="glu.controller.reportMan"> <message-listener message="needReportA" function="getReportA" /> <message-listener message="needReportB" function="getReportB" /> </controller> </controllers> <event-handlers> <event-handler name="dashboard"> <results> <result do="reportA" /> <result do="reportB" /> <result do="dashboardLayout" /> </results> </event-handler> <event-handler name="reportA"> <broadcasts> <message name="needReportA"> </broadcasts> <views> <view-page name="body" template="reportA.cfm" /> </views> </event-handler> <event-handler name="reportB"> <broadcasts> <message name="needReportB"> </broadcasts> <views> <view-page name="body" template="reportB.cfm" /> </views> </event-handler> <event-handler name="dashboardLayout"> <views> <include name="body" template="dashboard.cfm" /> </views> </event-handler> </event-handlers> </modelglue>
onTap: This framework offers another combination of nested and chained events. In most frameworks chained events in the queue are all processed before any content is delivered to the browser. In the onTap framework however, the "chained" events are executed after content is delivered, offering another method of speeding up slow-loading pages as an alternative to CFTHREAD by defering execution of some tasks until after the user is already viewing content. In both cases, nested and chained events are both executed via the CF_PROCESS custom tag.
Lets start with nested events:
<cfsavecontent variable="tap.view.content"> <div><cfinclude template="/inc/searchform.cfm"></div> <div style="float:left"> <cf_process netaction="reports/reportA"> </div> <div style="float:left"> <cf_process netaction="reports/reportB"> </div> </cfsavecontent>
To chain an event, all you have to do is add the attribute "netcallback" to the CF_PROCESS tag.
<cfset tap.view.content = "Your forum is deleted!" /> <!-- do this after you give the user his message, 'cause it takes a long time ---> <cf_process netaction="forum/deleteall" forumid="#attributes.forumid#" netcallback="true" />