| | 1 | = Formats = |
| | 2 | |
| | 3 | Often web sites are built for multiple front-end clients. One site may serve up pages to web browsers, mobile devices, Flex or AIR applications, or AJAX requests. Typically these clients all want the exact same data, but each will need to format the data in a slightly different manner. In the past, Model-Glue would typically require you to build multiple events to serve different flavored data results, or one event was used and the Controller fired a different result based on the other parameters. |
| | 4 | |
| | 5 | Model-Glue 3 formalizes this with a new requestFormat attribute. The requestFormat attribute is now a special value in the Event context. The <broadcasts>, <results> and <views> tags now support a format attribute. If specified, the enclosed message/result/include will only be executed if the requestFormat value matches. |
| | 6 | |
| | 7 | For example, imagine the following event created to look up and return employee data: |
| | 8 | |
| | 9 | {{{ |
| | 10 | <event-handler name="page.employee"> |
| | 11 | <broadcasts> |
| | 12 | <message name="needEmployee" /> |
| | 13 | </broadcasts> |
| | 14 | <results> |
| | 15 | </results> |
| | 16 | <views> |
| | 17 | <include name="body" template="employee.cfm" /> |
| | 18 | </views> |
| | 19 | </event-handler> |
| | 20 | }}} |
| | 21 | |
| | 22 | Now let's pretend we want to build an AJAX version of the site. We need to support both !JavaScript-enabled and disabled browsers so we want to keep the existing event. We would most likely simply add a new event. |
| | 23 | |
| | 24 | {{{ |
| | 25 | <event-handler name="ajax.employee"> |
| | 26 | <broadcasts> |
| | 27 | <message name="needEmployee" /> |
| | 28 | </broadcasts> |
| | 29 | <results> |
| | 30 | </results> |
| | 31 | <views> |
| | 32 | <include name="body" template="jsonemployee.cfm" /> |
| | 33 | </views> |
| | 34 | </event-handler> |
| | 35 | }}} |
| | 36 | |
| | 37 | Except for the event name, this is the exact same event except for the view. The view, jsonemployee.cfm, simply takes the Employee information and converts it to JSON. That's a lot of typing for one small change, and what happens if our message changes from needEmployee to needWageSlave? We have two places where we could forget to update our code. Model-Glue 3's format attribute helps solve this problem. Consider this new version: |
| | 38 | |
| | 39 | {{{ |
| | 40 | <event-handler name="employee"> |
| | 41 | <broadcasts> |
| | 42 | <message name="needEmployee" /> |
| | 43 | </broadcasts> |
| | 44 | <results> |
| | 45 | </results> |
| | 46 | <views format="html"> |
| | 47 | <include name="body" template="employee.cfm" /> |
| | 48 | </views> |
| | 49 | <views format="ajax"> |
| | 50 | <include name="body" template="jsonemployee.cfm" /> |
| | 51 | </views> |
| | 52 | </event-handler> |
| | 53 | }}} |
| | 54 | |
| | 55 | Now we can use the exact same event, but simply specify a different requestFormat. If we want to display the employee (assume ID represents the Employee's ID key), we could use this URL: |
| | 56 | |
| | 57 | {{{ |
| | 58 | http://localhost/index.cfm?event=employee&id=6&requestFormat=html |
| | 59 | }}} |
| | 60 | |
| | 61 | Model-Glue will default the requestFormat value to html. So this URL will display the exact same result: |
| | 62 | |
| | 63 | {{{ |
| | 64 | http://localhost/index.cfm?event=employee&id=6 |
| | 65 | }}} |
| | 66 | |
| | 67 | If we wanted to use the event via !JavaScript, we could then use this URL instead: |
| | 68 | |
| | 69 | {{{ |
| | 70 | http://localhost/index.cfm?event=employee&id=6&requestFormat=ajax |
| | 71 | }}} |
| | 72 | |
| | 73 | The format attribute also applies to the results tag. Let's continue to use our "Employee Detail" as an example. What if the employee ID requested doesn't exist? Our controller should probably fire off a result that our event can respond to: |
| | 74 | |
| | 75 | {{{ |
| | 76 | <cfset arguments.event.addResult("BadEmployee")> |
| | 77 | }}} |
| | 78 | |
| | 79 | But as with the views, we probably want to handle the result differently based on the type of request being made. As with the views tag, we can simply add a format attribute to the results tag. |
| | 80 | |
| | 81 | {{{ |
| | 82 | <results format="html"> |
| | 83 | <result name="BadEmployee" do="page.employees" /> |
| | 84 | </results> |
| | 85 | <results format="ajax"> |
| | 86 | <result name="BadEmployee" do="page.ajaxerror" /> |
| | 87 | </results> |
| | 88 | }}} |
| | 89 | |
| | 90 | In the block above we have two results with the same name. When our controller fires the "!BadEmployee" result, the only result tag that will actually run is the one that matches the current requestFormat value. For HTML we simply go back to an employee listing. For AJAX applications we could run a special event that returns an error code our front end AJAX code recognizes. |
| | 91 | |
| | 92 | Likewise, if a different message needs to be broadcast for the AJAX version of the event, the format attribute can also be used in the broadcasts tag. For example, suppose that the existing version of an event broadcasts a message indicating the need for a query resultset, and the AJAX version requires that the query be formatted by the QueryConvertForGrid() function for use with the <cfgrid> tag: |
| | 93 | |
| | 94 | {{{ |
| | 95 | <broadcasts format="html"> |
| | 96 | <message name="needEmployees" /> |
| | 97 | </broadcasts> |
| | 98 | <broadcasts format="ajax"> |
| | 99 | <message name="needEmployeesForGrid" /> |
| | 100 | </broadcasts> |
| | 101 | }}} |
| | 102 | |
| | 103 | Remember that Model-Glue will default the requestFormat value to html. You can override this default in the !ColdSpring.xml file by specifying a property for requestFormatValue. You can also change the value within your code itself. For example, you may use an onRequestStart in your controller to sniff out an iPhone browser: |
| | 104 | |
| | 105 | {{{ |
| | 106 | <cffunction name="onRequestStart" access="public" output="false"> |
| | 107 | <cfargument name="event" type="any"> |
| | 108 | <cfif findNoCase("iphone", cgi.http_user_agent) or findNoCase("ipod", cgi.http_user_agent)> |
| | 109 | <cfset arguments.event.setValue("requestFormat","mobile")> |
| | 110 | </cfif> |
| | 111 | </cffunction> |
| | 112 | }}} |
| | 113 | |
| | 114 | This code will examine the browser's user agent value and automatically set the requestFormat to mobile for both the iPhone and iPod Touch. |
| | 115 | |
| | 116 | Note: You may be wondering if there are required values for requestFormat. Absolutely not. You may name your formats any way you want. The values 'html' and 'ajax' were used just because they were the most familiar. You are free to use any values you want. |