You can manage the client-server interaction in several ways:
For Information on working with Spry, including how to use the cfsprydataset tag, see Using Spry with ColdFusion. For detailed information on using binding, including how to use binding with ColdFusion UI tags and the cfajaxproxy tag, see Binding data to form fields. For more information on using the ColdFusion Ajax-based UI tags, see Using Ajax UI Components and Features.
You can use the cfajaxproxy tag to create a client-side JavaScript proxy for a CFC and its functions. The proxy object has the following characteristics:
By using a ColdFusion Ajax proxy, any JavaScript code can call the proxied CFC functions. Thus, any Ajax application, not just one the uses ColdFusion Ajax UI elements, can use dynamic data provided by CFCs. Also, the proxy provides access to all of the functions in a CFC, not just the single function that you can specify in a bind expression.
Creating a JavaScript CFC proxy
The cfajaxproxy tag with a cfc attribute generates a JavaScript proxy that represents a CFC on the web client. Because a ColdFusion page that uses the cfajaxproxy tag is used as an Ajax client web page, the page typically starts with the cfajaxproxy tag (or tags), and the remainder of the page consists of the HTML and JavaScript required to control the display and perform the page logic on the client.
For more information about creating and using CFC proxies, see the cfajaxproxy tag in the CFML Reference.
The proxy provides several JavaScript functions that you use to control the behavior of the proxy:
When you use an Ajax CFC proxy, you can send to the CFC function any client-side data that can be serialized to JSON format, not just form data. However, the proxy cannot serialize DOM tree elements because they are wrappers on native code. Therefore, you cannot use DOM tree elements directly as parameters to a CFC function that you call by using an Ajax proxy. To ensure correct serialization to JSON for sending to the CFC, you must use basic JavaScript types only: array, object, and simple types. Instead of using a DOM element directly, you can pass only the specific element attributes that you require to the CFC function, either individually or in an array or object.
When you use the cfc attribute, you can submit form data to the CFC without refreshing the client page by calling the proxy setForm function before you call a CFC proxy function in your JavaScript. The proxy function then passes all field values of the specified form to the CFC function. In the CFC function Arguments scope, the argument names are the form control ID attributes (or, by default, the name attributes) and the argument values are the control values.
To pass the form parameters to your proxy function, you must invoke the proxy function immediately after you call the setForm function. Subsequent proxy function invocations do not get the form parameters.
If you also pass arguments explicitly to the CFC, cfargument tags in the CFC function that specify the explicitly passed arguments must precede any cfargument tags for the form fields. For example, you might have the following submitForm JavaScript function:
function submitForm() { var proxy = new remoteHandler(); proxy.setCallbackHandler(callbackHandler); proxy.setErrorHandler(errorHandler); proxy.setForm('myform'); proxy.setData('loggedIn'); }
In this example, the remoteHandler.cfc setData function should start as follows:
<cffunction name="setData" access="remote" output="false"> <cfargument name="loggedIn"> <cfargument name="userName"> ...
In this example, userName is the name of a form field. If the cfargument tag for userName preceded the cfargument tag for the loggedIn explicitly passed variable, the CFC function would not get the value of loggedIn. Your CFC function can omit cfargument tags for the form fields.
The following example uses a remote CFC method to populate a drop-down list of employees. When you select a name from the list, it uses a call to the CFC method to get information about the employee, and displays the results.
The main application page has the following lines:
<!--- The cfajaxproxy tag creates a client-side proxy for the emp CFC. View the generated page source to see the resulting JavaScript. The emp CFC must be in the components subdirectory of the directory that contains this page. ---> <cfajaxproxy cfc="components.emp" jsclassname="emp"> <html> <head> <script type="text/javascript"> // Function to find the index in an array of the first entry // with a specific value. // It is used to get the index of a column in the column list. Array.prototype.findIdx = function(value){ for (var i=0; i < this.length; i++) { if (this[i] == value) { return i; } } } // Use an asynchronous call to get the employees for the // drop-down employee list from the ColdFusion server. var getEmployees = function(){ // Create an instance of the proxy. var e = new emp(); // If you set a callback handler for the proxy, the proxy's calls // are asynchronous. e.setCallbackHandler(populateEmployees); e.setErrorHandler(myErrorHandler); // The proxy getEmployees function represents the CFC // getEmployees function. e.getEmployees(); } // Callback function to handle the results returned by the // getEmployees function and populate the drop-down list. var populateEmployees = function(res) { with(document.simpleAJAX){ var option = new Option(); option.text='Select Employee'; option.value='0'; employee.options[0] = option; for(i=0;i<res.DATA.length;i++){ var option = new Option(); option.text=res.DATA[i][res.COLUMNS.findIdx('FIRSTNAME')] + ' ' + res.DATA[i][[res.COLUMNS.findIdx('LASTNAME')]]; option.value=res.DATA[i][res.COLUMNS.findIdx('EMP_ID')]; employee.options[i+1] = option; } } } // Use an asynchronous call to get the employee details. // The function is called when the user selects an employee. var getEmployeeDetails = function(id){ var e = new emp(); e.setCallbackHandler(populateEmployeeDetails); e.setErrorHandler(myErrorHandler); // This time, pass the employee name to the getEmployees CFC // function. e.getEmployees(id); } // Callback function to display the results of the getEmployeeDetails // function. var populateEmployeeDetails = function(employee) { var eId = employee.DATA[0][0]; var efname = employee.DATA[0][1]; var elname = employee.DATA[0][2]; var eemail = employee.DATA[0][3]; var ephone = employee.DATA[0][4]; var edepartment = employee.DATA[0][5]; with(document.simpleAJAX){ empData.innerHTML = '<span style="width:100px">Employee Id:</span>' + '<font color="green"><span align="left">' + eId + '</font></span><br>' + '<span style="width:100px">First Name:</span>' + '<font color="green"><span align="left">' + efname + '</font></span><br>' + '<span style="width:100px">Last Name:</span>' + '<font color="green"><span align="left">' + elname + '</font></span><br>' + '<span style="width:100px">Email:</span>' + '<font color="green"><span align="left">' + eemail + '</span></font><br>' + '<span style="width:100px">Phone:</span>' + '<font color="green"><span align="left">' + ephone + '</font></span><br>' + '<span style="width:100px">Department:</span>' + '<font color="green"><span align="left">' + edepartment + '</font></span>'; } } // Error handler for the asynchronous functions. var myErrorHandler = function(statusCode, statusMsg) { alert('Status: ' + statusCode + ', ' + statusMsg); } </script> </head> <body> <!--- The form to display the employee drop-down list and employee data. ---> <form name="simpleAJAX" method="get"> List of Employees: <select name="employee" onChange="getEmployeeDetails(this.value)"> <script language="javascript"> getEmployees(); </script> </select> <br><br> <span id="empData"></span> </form> </body> </html>
The following component, which gets the data from the data source, must be in a file named emp.cfc in the components subdirectory of the application directory. The CFC uses the cfdocexamples data source that is installed with ColdFusion if you install the documentation.
<cfcomponent> <cfset this.dsn = "cfdocexamples"> <cffunction name="getEmployees" access="remote" returnFormat="json" output="false"> <cfargument name="empid" required="no" type="string" default="0"> <Cfquery name="qryEmp" datasource="#this.dsn#"> select * from Employees <cfif empid neq 0> where Emp_ID = #empid# </cfif> </Cfquery> <cfreturn qryEmp> </cffunction> </cfcomponent>