For instance, see the following script:
<cfscript>
try
{
//Your code that throws an exception
}
catch (e)
{
// This statement will be reached unlike
// in typical asynchronous model
}
</cfscript>
|
The ability to use asynchronous functions in <cfclient> through the ‘known’ synchronous model provides a lot of convenience while building mobile applications using ColdFusion.
Since ColdFusion automatically translates synchronous code to asynchronous code, exception handling becomes easier in client code.
The behavior of certain tags has been modified to support the asynchronous behavior. In the process, functionalities of some tags may differ. For instance, <cfloop> does not support the following features when used along with <cfclient>:
- Looping over a COM collection
- Looping over a date or time range
- Looping over a directory
Support for ColdFusion Functions
You can start writing mobile applications in ColdFusion using existing data types and functions. The <cfclient> tag supports CFML data types and functions.
The following functions depict usage of data types and functions in your ColdFusion-based mobile projects.
Using CFML simple types
The following example shows the usage of simple data types:
<cfclient>
<cfset myVar1 = 1>
<cfset myVar2 = “hello”>
<cfset myVar3 = true>
</cfclient>
|
Using CFML structures
The following example shows the usage of simple structures:
<cfclient>
<cfset myStruct = structNew()>
<cfset myStruct.key1= “hello”>
<cfif structKeyExists(myStruct, “key1”)>
...
</cfif>
</cfclient>
|
Using CFML arrays
The following example shows the usage of arrays:
<cfclient>
<cfset myArray = arrayNew(1)>
<cfset myArray[1] = “hello”>
</cfclient>
|
Using CFML functions
The following example shows the usage of functions:
<cfclient>
<cfif arrayLen(myArray) gt 1 >
...
</cfif>
<!--- using the math function--->
<cfset sum = arraySum(myArray) >
<!--- using the date/time function--->
<cfset currentDate = now() >
<!--- using the locale function--->
<cfset locale = getLocale() >
</cfclient>
|
List of all supported functions
The following list shows all the supported Array functions in client-side CFML:
- arraySlice
- arrayAppend
- arrayIsDefined
- arrayAvg
- arrayIsEmpty
- arrayClear
- arrayLen
- arrayMax
- arrayNew
- arrayMin
- arraySort
- arrayDelete
- arrayToList
- arrayPrepend
- isArray
- arrayResize
- listToArray
- arraySet
- arrayFind
- arrayFindAll
- arraySum
- arraySwap
- arrayFindNoCase
- arrayFindAllNoCase
The following Array function is NOT supported:
- arrayFilter (closure function)
The following list shows all the supported Structure functions in client-side CFML:
- isStruct
- structDelete
- structAppend
- structInsert
- structClear
- structIsEmpty
- structCopy
- structKeyExists
- structCount
- structNew
- structFind
- structUpdate
- structFindKey
- structFindValue
- structGet
- structKeyArray
- structKeyList
- structSort
The following list shows all the supported List functions in client-side CFML:
- find
- findNoCase
- findOneOf
- formatBaseN
- lCase
- left
- len
- listAppend
- listChangeDelims
- listContains
- listContainsNoCase
- listDeleteAt
- listFind
- listFindNoCase
- listFirst
- listGetAt
- listInsertAt
- listLast
- listLen
- listPrepend
- listQualify
- listRest
- listSetAt
- listSort
- listToArray
- listValueCount
- listValueCountNoCase
- replaceList
- valueList
The following List function is NOT supported:
The following String functions are NOT supported:
- binaryEncode
- binaryDecode
- charsetEncode
- charsetDecode
- toBase64
- toBinary
- toString
- uRLDecode
- uRLEncodeFormat
- lSParseNumber
- lSParseCurrency
- lSParseEuroCurrency
- lSIsDate
- lSIsNumeric
- lSIsCurrency
The following Regex functions are supported:
- rEFind
- rEMatch
- rEFindNoCase
- rEMatchNoCase
- rEReplace
- rEReplaceNoCase
The following Math function is NOT supported:
The following Date functions are NOT supported:
- createODBCDate
- createODBCTime
- createODBCDateTime
- lSDateFormat
- lSIsDate
- lSParseDateTime
- lSTimeFormat
The following utility functions are supported:
- isBoolean
- isDefined
- decimalFormat
- isNumeric
- dollarFormat
- isNull
- htmlCodeFormat
- isSimpleValue
- htmlEditFormat
- isValid
- numberFormat
- createUUID
Support for custom tags
You have been using custom tags in ColdFusion for the past few releases of ColdFusion. Custom tags allowed you to extend CFML by adding your own tags to the ones shipped with ColdFusion. Custom tags can now be created in <cfclient> too. The following sections provide an overview of the supported features and restrictions while using custom tags for building mobile applications.
Note: Application and Server mappings are also supported in custom tags.
Paths for custom tags
Custom tags are detected when they are made available in the following locations:
- The custom tag available in the same directory as the calling page
- The custom tag available in the cfusion/CustomTags directory
- The custom tag available in sub-directories under the cfusion/CustomTags directory
- The custom tag available in server/application mapped folders
Invoking custom tags
The custom tags can be invoked in the following ways:
- Using the cf_<tagname>. For instance, by calling <cf_mytag>
- Using the <cfmodule> tag. For instance, <cfmodule template="../cf_mytag.cfm">
- Also, <cfmodule name=”tags.mytag”>
- For the <cfimport> tag, we use the taglib to import the custom tags:
- For instance, <cfimport prefix = “myTags” taglib = “/custom”>
- The DOT(.) notation can be used to access custom tags available inside sub directories. For instance, use <cfmodule name = “tags.mytag”>
<cfimport> supports only path to custom tags and hence you cannot have JSP tag libraries.
Passing values
You can pass values to a custom tag using a name-value pair:
<cf_mytag myname=#myvalue#>
|
Also, multiple name-value pairs can be passed to a custom tag:
<cf_mytag myname1=#myvalue1# myname2=#myvalue2#>
|
To access the arguments passed to the custom tag, the custom tag CFM file can use the attributes scope as follows:
#attributes.myname1# and #attributes.myname2#
|
To send the data back to the calling page, the custom tag CFM file can use the Caller scope as follows:
<cfset caller.myname=#attributes.myname1# & " " & #attributes.myname2#>
|
You can also pass a struct to the custom tag:
<cfset args=structNew()>
<cfset args.x = "‐X‐">
<cfset args.y = "‐Y‐">
<cf_mytag arg1="value1" attributeCollection=#args# anotherarg="16">
|
Tag instance data
When a custom tag page executes, ColdFusion keeps data related to the tag instance in the thisTag structure. You can access the thisTag structure from within your custom tag to control processing of the tag.
To determine if an end tag is specified, use the hasEndTag as follows:
<cfif thisTag.hasEndTag is 'false'>
<!‐‐‐ Abort the tag‐‐‐>
<cfabort />
</cfif>
|
To determine the tag execution mode, use the executionMode attribute. Three modes are supported:
- Start mode – For processing the start tag
- End mode – For processing the end tag
- Inactive mode – For processing custom tags using nested tags
<cfif thisTag.executionMode is 'start'>
<!‐‐‐ Process start tag ‐‐‐>
<cfelseif thisTag.executionMode is 'end'>
<!‐‐‐ Process end tag ‐‐‐>
</cfif>
|
You can access the body text within the custom tag using the thisTag.generatedContent variable. You can modify this text during processing of the tag. The contents of the thisTag.generatedContent variables are returned to the browser as part of the tag’s output. The content includes all text and HTML code in the body, the results of evaluating ColdFusion variables, expressions, and functions, and the results generated by descendant tags.
See the following example:
<cfif thisTag.executionMode is 'end'>
<cfset thisTag.generatedContent ='<!‐‐#thisTag.generatedContent#‐‐>'>
</cfif>
|
The nested sub tag can pass its attributes to the parent tag. A sub tag can use cfassociate to communicate its attributes to the base/ancestor tag.
<cfassociate baseTag="tagName" dataCollection="collectionName">
|
The following code shows how you can access the subtag attributes in the base tag:
<cfparam Name='thisTag.assocAttribs' default=#arrayNew(1)#>
|
You can also access the ancestral data in the sub tag using the getBaseTagList() helper method as follows:
<cfset ancestorlist = getBaseTagList()>
|
The getBaseTagList() method returns a comma-delimited list of uppercase ancestor tag names, as a string. You can also use the getBaseTagData() method to return an object that contains all the variables of the nth ancestor.
Aborting custom tag processing
The <cfexit>/<cfabort> tag exits the page execution.
Deviation list for custom tags
The following list contains some known issues and deviations in behavior of the custom tags:
- In <cfclient>, variables scope is supported. But you have to explicitly scope it.
Server-side CFML
|
Client-side CFML
|
caller.cfm
<cf_customtag value1="old_value">
<cfoutput>
#variables.old_value#
<cfoutput>
<cfoutput>
#old_value#
<cfoutput>
|
customtag.cfm
<cfset caller[attributes.value1]="new_value"/>
|
|
caller.cfm
<cfclient>
<cf_customtag value1="old_value" >
<cfoutput>#variables.old_value#<cfoutput>
</cfclient>
|
customtag.cfm
<cfset caller[attributes.value1]="new_value"/>
|
|
- If you use the "#attributes.attributename#" syntax in the custom tag after an asynchronous call, you will see an unexpected behavior.
Server-side CFML
|
Client-side CFML
|
<cfset divid = "#attributes.div_id#">
|
|
<cfset divid = "#attributes.div_id#">
|
The above code will not work.
Use:
<cfset divid = #attributes.div_id#>
|
|
Numeric values passed to the attributes in caller are passed as a string to the custom tags:
In the above example, attr1 is converted to a number, if you are accessing the attribute in a numeric operation. However, it does not work in this manner for client-side custom tags. You need to use:
Or:
<cfset x = 1>
<cf_custom attr1=#x#>
|
Type conversion is not handled in client custom tags.
- Function declared in the caller CFM is accessible in the custom tag (CFM) using the caller.functionname() on the server-side. However, this is not the behavior on the client side.
Server-side CFML
|
Client-side CFML
|
<cffunction name="func1">
<cfretrurn "Hello">
</cffunction>
<cf_custom>
<cfset caller.func1()>
|
|
The functions defined in the caller CFM are not available in the custom tags.
|
- Using variables to pass the path of the included file does not work inside <cfclient>.
Server-side CFML
|
Client-side CFML
|
<cfset path="someCFM.cfm">
<cfinclude template=#path#>
|
|
This is not supported.
|
- Passing the template/name (with <cfmodule>) attribute as a variable does not work with <cfclient>.
Server-side CFML
|
Client-side CFML
|
<cfset path="someCFM.cfm">
<cfmodule template=#path#>
|
|
This is not supported as we need to do the translation during the compile time itself.
|
- Exception thrown in the custom tag template will not be handled by the exception handler defined in the caller CFM. If the custom tag name is wrong or if the included CFM name is wrong, in client-side CFML, you will get an exception during the compilation time itself.
Note: Based on the location of the JavaScript file (specified in the <cfinclude> tag or using the <script> tag), the order of execution of statements differ. |
Non-<cfclient> custom tags cannot be called from caller CFMs of <cfclient>. Also, a client-side custom tag cannot have server-side ColdFusion tags outside the <cfclient> tag. This is true for client-side included-CFMs too. For better debugging, do not add script blocks/link tags/style tags in the client-side custom tags. Always create a separate JavaScript file or a CSS file and add them using the <cfinclude> tag.
<cfinclude template="utils.js">
or
<cfinclude template="new.css">
|
This is applicable for client-side included CFMs too.
Support for CFC (Client-side and Server-side)
A client-side CFC can be written using the client=true attribute for a cfclient component. For instance, a client-side CFC can identify itself by having client=true along with other component attributes. See the following example:
component client=true
{
public function foo()
{
//some code here
}
}
|
<cfclient> communicates with the ColdFusion Server quite seamlessly so much so that you can create objects of a server component and call functions on that object just like how you do ColdFusion Server programming. The ColdFusion Server facilitates all the various interactions required between a mobile client and the server without any restrictions on the language.
See the following example:
<cfclient>
<!-- Create a JS proxy of server side component myCFC.cfc‐‐‐>
<cfset proxy = new app1.controls.myCFC(id)>
<!-- Update some data ‐‐‐>
<cfset proxy.setVar("myVar1")>
<cfset proxy.setProperties(someStructVar)>
</cfclient>
|
In the above example, you are calling a function on a remote CFC within the <cfclient> tag. The new operator creates a proxy to the server CFC. You can use the instantiated CFC object to invoke remote functions on that CFC.
Note that a server CFC is similar to any other CFC without the client attribute being set to true.