This post is reproduced from my post at my personal blog ramkulkarni.com.

So far I have posted CFMobile examples that were mostly standalone applications (except a photo application that uploaded image to server). However many mobile applications may need to interact with server, for example to show data from a remote database, to modify data or for many other purposes.

CFMobile features in ColdFusion Splendor make accessing remote CF server very easy. I will demonstrate this using a simple example - I will build a mobile app that displays employee records fetched from a remote CF server. The client side (cfclient) code calls a CFC on the server side which fetches data and returns result to the calling page. You will see that creating and accessing a server side CFC is as easy as it is in a completely server side CFML code - you don't need to worry about writing code to make AJAX calls. cfclient does that for you transparently. I should mention here that this feature to call server CFCs from cfclient is not limited to mobile application, you can even use it for any web application.

Here is a screenshot of the application

 

I will start with building the server side application. We need to create a database and a table on the server. I am going to use Embedded Apache Derby database for this application. Using ColdFusion Administrator, you can create both database and datasource for Embedded Apache Derby. Open up the administrator and go to 'Data & Services'->Data Sources page and add a new data source, called EmployeeDS -

Click Add button, and you will see details page -

Specify database folder and select 'Create Database' option. I have created the database in cfusion/db/EmployeeDS folder. Derby database driver creates the last folder, so make sure EmployeeDS folder does not already exist in cfusion/db, otherwise Derby throws error.

We now need to create employee table. I have created a simple cfml file, db_scripts.cfm with functions to create database, list and delete records.

<!--- Functions to create Employee databsase, display employees 
	and delete all employees from the table --->

<!--- Comment call to function createTable after table is successfully created --->
<cfset createTable()>

<!---<cfset deleteAll()>--->

<!---<cfset listEmployees()>--->

<br>Script Executed.

<cffunction name="createTable" >

	<cfquery datasource="employeeDS">
		create table employee (
			id integer not null generated always as identity,
			first_name varchar(20),
			last_name varchar(20),
			address varchar(100))
	</cfquery>
</cffunction>

<cffunction name="deleteAll" >
	<cfquery datasource="EmployeeDS" >
		delete from EMPLOYEE
	</cfquery>
</cffunction>

<cffunction name="listEmployees" >
	<cfquery datasource="employeeDS" name="rs">
		select * from EMPLOYEE order by FIRST_NAME
	</cfquery>

	<table >
		<tr>
			<th>First Name</th>
			<th>Last Name</th>
			<th>Address</th>
		</tr>
		<cfoutput query="rs">
			<tr>
				<td>#first_name#</td>
				<td>#last_name#</td>
				<td>#address#</td>
			</tr>			
		</cfoutput>
	</table>
</cffunction>

Run this page and it will create employee table with fields id, first_name, last_name and address.

Next I will create a server side CFC, EmployeeDBManager.cfc with two functions - getEmployees and addEmployee -

<cfcomponent >
	<cfset this.ds = "employeeDS">

	<cffunction name="getEmployees" returntype="Array" access="remote" returnformat="JSON" 
		hint="Fetches employee rows from Employee table and returns array of EmployeeTO components">

		<cfset result = ArrayNew(1)>

		<cfquery datasource="#this.ds#" name="empRs">
			select * from EMPLOYEE order by FIRST_NAME
		</cfquery>

		<cfloop query="empRs">
			<cfset var empStruct = {"id":id, "firstName":first_name, 
									"lastName": last_name, "address":address}>
			<cfset arrayAppend(result,empStruct)>
		</cfloop>

		<cfreturn result>

	</cffunction>

	<cffunction name="addEmployee" access="remote" returntype="numeric" 
		hint="Inserts a new employee record in the able">
		<cfargument name="emp" type="struct" >

		<cfquery datasource="#this.ds#" result="newEmpResult">
			insert into EMPLOYEE (FIRST_NAME,LAST_NAME,ADDRESS) values (
				<cfqueryparam cfsqltype="cf_sql_varchar" value="#emp.firstName#">,
				<cfqueryparam cfsqltype="cf_sql_varchar" value="#emp.lastName#">,
				<cfqueryparam cfsqltype="cf_sql_varchar" value="#emp.address#">
			)
		</cfquery>

		<cfreturn newEmpResult.generatedKey>
	</cffunction>

</cfcomponent>

Note that both the functions are marked remote (because they will be called from a cfclient block).
getEmployee returns Array in JSON format. It returns array of Struct with fields id, fistName, lastName and address.
addEmployee takes Struct argument with the same fields as above, except id. It returns id of the newly added employee.
We are done with the server side code for this application.

Let's now create the client side application. In index.cfm of the client app, I first create HTML UI and write some JavaScript event handlers.

<DOCTYPE html>

<script src="jquery-2.0.3.min.js" ></script>

<script >
	$(document).ready(function(){

		$(document).on("click","#addBtn", function(){
			var firstName = $("#fnTxt").val();
			var lastName = $("#lnTxt").val();
			var city = $("#cityTxt").val();

			if (firstName.trim().length == 0)
			{
				alert("First name is required");
				return;
			}

			addEmployee(firstName,lastName,city);
		});
	});
</script>

<style >
	th,td {
		text-align:left;
	}	
</style>

<h2>CFMobile Demo:</h2>
This application calls a CFC on the server side to get all employee records from a database table on the server.<br>
You can add an employee by filling up following details and clicking Submit button.
This again makes call to a server CFC to add employee to the table.

<h3>Add Employee:</h3>
<form>
	<table >
		<tr>
			<td>First Name:</td>
			<td><input type="text" id="fnTxt">		
		</tr>
		<tr>
			<td>Last Name:</td>
			<td><input type="text" id="lnTxt">		
		</tr>
		<tr>
			<td>City:</td>
			<td><input type="text" id="cityTxt">		
		</tr>
		<tr>
			<td colspan="2">
				<button type="button" id="addBtn">Add</button>
				<button type="reset">Reset</button>
			</td>
		</tr>
	</table>
</form>
<hr>

<h3>Employees:</h3>
<table id="empTable" width="100%">
	<tr>
		<th>First Name</th>
		<th>Last Name</th>
		<th>City</th>
	</tr>
</table>

<cfclient>

    <cfscript>
    </cfscript>
</cfclient>

In the cfscript block in cfclient, I first instantiate the server side CFC, EmployeeDBManager, and then call getAllEmployees function.

try
{
	empMgr = new EmpServerApp.EmployeeDBManager();
}
catch (any e)
{
	alert("Error : " + e.message);
	cfabort ();
}

//get all employees from the server and display in the above HTML table
getAllEmployees();

empMgr is a global variable. You can create page level variable also using variables prefix, i.e variables.empMgr.
Notice that you instantiate server CFC from cfclient block just as you would do it in server side code.

In getAllEmployees, I call getEmployees method of the server CFC. But before calling the server CFC, I set callback handler (function) which will be called when server function returns.

//Fetch employees data from server and display in the HTML table
function getAllEmployees()
{
	try
	{
		//Set callback function on the server CFC, which will be
		//called with the result
		empMgr.setCallbackHandler(function(callbackResult){
			var employees = callbackResult.result;
			var empCount = arrayLen(employees);
			for (var i = 1; i <= empCount; i++)
			{
				addEmpToHTMLTable(employees[i]);	
			}
		});

		empMgr.getEmployees();
	}
	catch (any e)
	{
		alert("Error : " + e.message);
		return;
	}

}

If you do not set the callback handler, remote CFC function would be called synchronously, which will block application UI till the CFC function returns. So make sure you set callback handler when invoking remote CFC function from cfclient.

Argument to the callbakc handler is an object with result field. This field actually contains result returned by the remote CFC function. getEmployee function of the CFC returns array (of struct/object), so I iterate over it and call addEmpToHTMLTable function for each employee struct.

<!--- Append employee data in the HTML table --->
<cffunction name="addEmpToHTMLTable" >
	<cfargument name="emp" >

	<cfoutput >
		<cfsavecontent variable="rowHtml" >
			<tr>
				<td>#emp.firstName#</td>
				<td>#emp.lastName#</td>
				<td>#emp.address#</td>
			</tr>
		</cfsavecontent>
	</cfoutput>

	<cfset $("##empTable").append(rowHtml)>
</cffunction>

There is one more function in the cfscript block of cfclient, to add new employee

//Add a new employee.
function addEmployee(firstName, lastName, city)
{
	try
	{
		var newEmp = {"firstName":firstName, "lastName":lastName, "address":city};

		//Set callback function on the server CFC, which will be
		//called with the result
		empMgr.setCallbackHandler(function(callbackResult) {
			newEmp.id = callbackResult.result;
			addEmpToHTMLTable(newEmp);
		});

		empMgr.addEmployee(newEmp);
	}
	catch (any e)
	{
		alert("Error:" + e.message);
		return;
	} 
}

addEmployee (in cfclient) takes three arguments -  firstName, lastName and city (address). I create a new struct using these arguments and pass it to addEmployee method of the remote CFC (EmployeeDBManager). Here also I set the callback handler because I don't want call to a server function blocking the application.
addEmployee function on the server side returns id of the new employee. I get this as result field of the argument to callback handler. Then I call addEmpToHTMLTable (see above) to append new employee to the HTML table.

This completes code for the application. You can open index.cfm of the client application in Chrome/Safari and see how the application works. You can also test it on mobile as a standalone application using PhoneGap Shell app that we have built (see links in my earlier post - Simplify Mobile Application Development Using ColdFusion).

However if you package the client application and install it on mobile device, you will find that application does not work - no data is fetched from the server.
When resolving URL of remote CFC in cfclient, the framework tries to resolve it from the URL of the client page. If client page and server CFC are loaded from the same server, which is what happens when you run the application in desktop browser or in the Shell application, cfclient is able to resolve the server CFC. But it cannot resolve it in a packaged application, because the client page is loaded locally from the device and server side CFC does not exist on the device.

To help resolve server CFCs (used in cfclient), you need to provide base URL of the server when packaging the application. You do that by going to project properties (right click the project in the Navigator view of ColdFusion Thunder and select Properties menu option)->ColdFusion Mobile Project-> Miscellaneous page and specifying 'Application Base URL'

When you right click on the project and select 'Generate PhoneGap Build' menu option, the above URL will be used in the generated code to resolve server side CFCs.

You also need to provide access to the external server from your mobile application. To do that, go to PhoneGap tab (in Mobile Project Properties) and click  New button. Go to Access page and type IP of the external (CF 11) server or * to allow access to any external server.

 

Download CFBuilder projects for this application. EmpMobileApp folder in this zip contains client side application and EmpServerApp folder contains server side app. I am not providing Android APK file for this app because my server side CFC will not be accessible from this APK when you install it on you device.

Though I showed you how to access remote database from CFMobile application in this post, the technique is not limited to database access. Server CFC can get data from any source and return to cfclient.

-Ram Kulkarni

Update : Final build of ColdFusion 11 has a bug because of which access to CFC on the server does not work. To fix this issue, copy cfclient_main.js to wwwroot/CFIDE/cfclient folder of the server. Make sure you keep back-up of the old file before you overwrite it.

23 Comments to “CFMobile Example – Accessing remote data from mobile application”

  1. Tayyab Hussain
    Thanks Ram, This was what i was looking for though I tried and if my experiment is successful I'll share it with you. I tried this by writing a simple web service and calling this web service from the CFML Client side. I hope it works out too
  2. Tayyab Hussain
    Ok!! Basically the whole crux of connecting the device with server lies in the last part of the article where you specify your server in the miscellaneous tab before packaging it with PhoneGap. One more thing in the EmployeeDBManager.cfc you returned the array in JSON format. is it necessary??
  3. Ram Kulkarni
    You are right, it is not necessary to specify return format as JSON. We use the same framework that was used in cfajaxproxy and that framework serializes data to JSON.
  4. Tayyab Hussain
    These are the 2 most simplest coldfusion files. One is a cfc and the other a CFM but when I wrap the cfm into <cfscript> tag I get a blank page.
    listCustomers.cfm
    <cfinvoke component="customer"
       method="retrieveCustomers"
       returnvariable="allCustomers"></cfinvoke>
    <table width="100%" border="1" cellspacing="0" cellpadding="3">
    <tr>
    <td>First Name</td>
    <td>Last Name</td>
    <td>Email</td>
    </tr>
    <cfoutput query="allCustomers">
    <tr>
    <td>#firstName#</td>
    <td>#lastName#</td>
    <td>#email#</td>
    </tr>
    </cfoutput>
    </table>

    The most simplest example say

    <cfclient>
    <cfset var="hello World">
    <cfoutput> #var# </cfoutput>
    </cfclient>

    even gave me a blank page

    Please help.

    customer.cfc
    <cfcomponent displayname="Customer" hint="ColdFusion Component for Customers">
       <cfset this.dsn="books">
    <!--- This function retrieves all customers from the database --->
    <cffunction name="retrieveCustomers"
       hint="Gets all customer from the database" returntype="query" access="remote" >
    <cfquery name="getCustomers" datasource=#this.dsn#>
        select * from Customers
    </cfquery>
    <cfreturn getCustomers>
    </cffunction>
    </cfcomponent>
  5. Ram Kulkarni
    I have explained a solution in a new post CFMobile - How to display CF query data returned from remote CFC (http://blogs.coldfusion.com/post.cfm/cfmobile-how-to-display-cf-query-data-returned-from-remote-cfc)

    Regarding the simplest example you posted, you need to change variable name 'var', it is a reserved word. So If you have -
    <cfclient>
    <cfset var1="hello World">
    <cfoutput> #var1# </cfoutput>
    </cfclient>

    then it should work.
  6. Tayyab Hussain
    Thanks for pointing out, Yes "var" is a reserved word.
  7. indianmesh
    Wonderful information thanks for sharing with us.....

    <a href="http://www.indianmesh.com">web development company</a>
  8. mobile app development
    I really enjoyed the quality information you offer to your visitors for this blog. I will bookmark your blog and have my friends check up here often.
  9. Freddy Moncayo
    The application worked fine in a browser but in the Android Simulator (from eclipse AVDM) the application does not work - no data is fetched from the server. What should I check?
  10. Ram Kulkarni
    @Freddy are running the app in an Emulator browser? Or did you package the application?

    I would check if request from the app is reaching server - use server debugger of CFB or use cfdump to write debug message to a file.
  11. Tarquin Hall
    The advantage of using the software on the move makes mobile apps very popular across the masses. It's a nice article given here.
  12. Freddy Moncayo
    Thanks Ram for your reply. I installed and apk file in the Virtual Device. The application opens fine but the Employees list is empty. When I open the cfc file from the browser (in the Android VD) it seems to be fine. I created a cfm file to consume the cfc file and the data is correctly retrieved in the VD (using the Internet Browser). Should I try a real device or it would be the same?
  13. Ram Kulkarni
    @Freddy, open mobile project properties in CFB and go to "ColdFusion Mobile Project" page. Click PhoneGap tab. Click New button. Go to Access page and type * in Origin filed. Save the change. Also make sure you have set 'Application Base URL" as described in the blog. Package the application again.
  14. Wil
    Hey Ram,

    This example shows how to call a webservice that is on the same machine as the cfclient code.
    I am looking to consume a webservice that is located on a different server to use the data in my app.
    For my situation, would I replace the cfquery code in the employeemanagerdb.cfc file with a cfinvoke-webservice? Thus having my cfclient code calling a local remote cfc which then calls the foreign server's webservice?
  15. Ram Kulkarni
    For packaged mobile application, you can specify the URL of the remote server in project properties->ColdFusion Mobile Project->Application Base URL.
    The URL cannot be set in case of a web application. In that case you can use XHR to invoke REST API.

    But from your comment it appears that cfclient calls a CFC from the same server as from where page is loaded and that CFC calls web service from another server. For the second web service call, cfclient does not come into picture at all. So cfinvoke should work in that case.
  16. Mark
    So I'm trying to build my first remote access phone app using Coldfusion Builder 3 and found this page. I went through the demo code for Building Your First Mobile App With Coldfusion 11 at http://www.adobe.com/devnet/coldfusion/articles/build-your-first-mobile-app.html - that went well but the database is local on the phone. I need to learn to access a remote dB.

    So I downloaded the example files linked here. I put the server files in <my IP>/mobile/ and ran the db_scripts.cfm to create the employee table. Then I put the EmpMobileApp files in my wwwroot directory, set CFB3 parameters including the Application Base URL to <my IP>:8600/mobile and did the Generate Phonegap Build, got my APK file, put it on my phone and when I run the App I get a error: EmpServerApp is not defined

    So I'm assuming the mobile app is not finding the remote server at all on <my IP>/mobile. I'm assuming the EmpServerApp variable is from the Application.cfm file on the remote host <cfapplication name="EmpServerApp">

    So where do I go from here, how can I troubleshoot this. I want to know if the mobile app is trying to contact the remote host. I noticed the example here uses <mp IP>:8600 where CFB3 uses the example <my IP>:8500/[context root]
  17. Ram Kulkarni
    @Mark, application base url should be up to doc root and should not include folders unders doc root. So try setting application base URL to <my_ip>:8600/. Next, you should change CFC path in the client code (index.cfm in EmpMobileApp). I had assumed in the blog that you would copy EmpServerApp under wwwroot, so CFC was created as -
       empMgr = new EmpServerApp.EmployeeDBManager();
    You will need to change this to
       empMgr = new mobile.EmpServerApp.EmployeeDBManager();
    or if you have copied files from EmpServerApp directly under mobile folder then -
       empMgr = new mobile.EmployeeDBManager();

    -Ram
    Adobe ColdFusion Team
  18. Mark
    Hi Ram, thanks for the quick response, unfortunately it didn't make a difference. I've changed the base URL to http://<my IP>:8600/ I changed the directory on the server from mobile to EmpServerApp so it conforms to the original structure. But I still get the

    error: EmpServerApp is not defined

    I had originally made the changes suggested above but then I got:

    error: mobile is not defined

    So not sure where to go from here.
  19. Ram Kulkarni
    @Mark, I tested the app again and was able to run it fine. Make sure you I follow these steps :

    - Unzip project files unders wwwroot. So you should have wwwroot/EmpServerApp and wwwroot/EmpMobileApp folders. Make sure server is ColdFusion 11
    - Import both the projects in CFBuilder 3
    - Make sure the proper server is associated with these projects in the project properties
    - Create EmployeeDS datasource in the CF Administrator
    - Run EmpServerApp/db_scripts.cfm file to create tables
    - Run EmpMobileApp/index.cfm in Chrome/Safari and make sure application works. Add a new employee and make sure you see details in the list.
    - Replace wwwroot/CFIDE/cfclient/cfclient_main.js with the file linked at the bottom of the post. This is the patch for a bug.
    - Right click on EmpMobileApp project and go to 'ColdFusion Mobile Project'->Miscellaneous table.
    - Enter http://<your_server_ip>:<port>; as Application Base URL
    - Click on PhoneGap tab. Click New button and click Access in the left pane. Type * in origin field. Save changes.
    - Right click on EmpMobileApp project and select Generate PhoneGap Build menu.

    Once you download and install the packaged app on your device, you should see records already added in the employee table. You should also be able to add new employees from this app.
  20. Mark
    Hi Ram, thanks for the reply. I'll give it another try. To clarify though there is some variation on where I'm building this and where I'm testing.

    I'm building the app on my desktop using CFB3, that has a built in CF11 server, etc. But the MSSQL database sits on a hosting account that runs CF 7.0.2, I don't have CF admin access on that but I have a datasource setup, so I'm using that datasource and changing the code accordingly in db_scripts.cfm. I've created the EMPLOYEE table manually and entered some data.

    I did unzip the files into wwwroot on my desktop, and now that I have the EmpServerApp files there it's not generating the error anymore from the APK file but it's not reading the remote database either, no data shown and no data added. I've got the base URL set and the remote access allowed and the new script client_main.js installed on my desktop.

    I'll go through the build again, just in case I missed anything. I think I'm getting a little confused on what files need to be where, the Client and Server files on my desktop with CFB3 in wwwroot for the build and the files on the remote CF 7.0.2 server where the MSSQL dB exists. I'm assuming just the server files need to be there in ?? directory.
  21. JR
    Hi there,

    I have been trying to get this going with no luck.

    I went and created the projects in CF Builder 3 and everything works OK on the browser. One change I made was to create a SQL Server database and the Employee table in there. Again, in the browser works OK with records being inserted into the DB and retrieved OK.
    I Replaced wwwroot/CFIDE/cfclient/cfclient_main.js with the file linked at the bottom of the post.
    I also Right clicked on EmpMobileApp project and went to 'ColdFusion Mobile Project'->Miscellaneous table.
    I also Entered http://127.0.0.1:8600 as I am running everything in my local machine as Application Base URL
    I also Typed * in origin field.
    When I create the phonegap build, I don't see any data from the database. Nothing happens when I try to enter a record but I get no errors. Any ideas?
  22. Ad Groen
    I have the same problem as JR describe above.
    When I create the phonegap build, I don't see any data from the database. Nothing happens when I try to enter a record but I get no errors. Any ideas?
    Is there already a solution for this problem.
    Everythings works except when packaging the application and intstall the APK on a mobile device, you see no database records form the server via CFC.
    Untill now i have not find a solution for this problem.
  23. Knut
    Nearly everything worked fine for me, but I had problems with displaying the 'employee' table data. It took a little while to find the reason why.

    After activating "Preserve case for Struct keys for Serialization." under "Server Settings > Settings" in the ColdFusion Admin for the CF-server everything worked fine for me.

Leave a Comment

Leave this field empty: