Passing Form Data from a jQuery Ajax Call to a CFC Function and Returning It

One of the bigger upgrades I did at my job some years ago was to pass form data using jQuery into a CFC, validating it, and then returning any necessary validations or allowing a user to proceed the next step. I used two functions to prepare the data before sending it to a CFC.

Here are the necessary script files:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

json2.js can be downloaded here:
https://github.com/douglascrockford/JSON-js

The two functions:

<script>
	$.fn.serializeObject = function()
	{
	    var o = {};
	    var a = this.serializeArray();
	    $.each(a, function() {
	        if (o[this.name] !== undefined) {
	            if (!o[this.name].push) {
	                o[this.name] = [o[this.name]];
	            }
	            o[this.name].push(this.value || '');
	        } else {
	            o[this.name] = this.value || '';
	        }
	    });
	    return o;
	};
	
	var PrepJSON = function(frmObj) {
		var o = {};
		o = JSON.stringify(frmObj.serializeObject());
		return o;
	};
</script>

The serializeObject function was found here: https://stackoverflow.com/a/5181003 and the JSON stringify part here: https://stackoverflow.com/questions/1184624/convert-form-data-to-javascript-object-with-jquery?page=1&tab=votes#comment4948246_1184624

With those called earlier in an application, we can now tell a submit button to ready our form data before passing it into a CFC using jQuery’s Ajax call.

<script>
$(function() {
	$("#btnSubmit").click(function() {
		//Create variable to store form object
		var frmObj = $("#myForm");

		//Store json string of form data
		var frmData = PrepJSON(frmObj);

		//Call CFC to process the form.
		$.ajax({
			type: 'POST',
			url: "CFCUpdate.cfc?method=ProcessForm"
			,data: ({ frmData: frmData })
			,success: function(data) {
				//Next step goes here.
			  }
			  ,error: function (xhr, textStatus, errorThrown){}	
		});
		return false;
	});
});
</script>

The CFC itself that we are calling:

<cffunction name="ProcessForm" access="remote" output="false" returntype="string" returnformat="plain">

	<cfargument name="frmData" required="yes" type="string">
	<cfset var formStruct = {} />

	<cfset formStruct = DeserializeJSON(arguments.frmData)>

	<!--- Do any necessary processing here--->

	<cfreturn "OK">
</cffunction>

Make sure you have debugging off so that none of it returns through the CFC string. I put something along the lines of the following in any relevant application.cfm or Application.cfc files.

<cfif LCase(Right(script_name,3)) is "cfc">
	<cfsetting showdebugoutput="no">
</cfif>

At a point in time, I thought I might need to return and update the form data as well and encountered a few issues. Since then, I have actually not had a situation where I need to return the entirety of form data and reflect an update, but since I went through the trouble of learning it and logging it at work, I may as well note it on this website as well for any visitors and as possible reference for if I do ever need it after all.

Get the jQuery Field plugin here: https://pengoworks.com/workshop/jquery/field/field.plugin.htm

Here, you’ll see a few changes from our function earlier that I will highlight:

$(function() {
	$("#btnSubmit").click(function() {
		//Create variable to store form object
		var frmObj = $("#myForm");

		//Store json string of form data
		var frmData = PrepJSON(frmObj);

		//Call CFC to process the form.
		$.ajax({
			type: 'POST',
			url: "CFCUpdate.cfc?method=ProcessFormv1
			,data: ({ frmData: frmData })
			,dataType: "json"
			,success: function(data) {
				frmObj.formHash(data);
			  }
			  ,error: function (xhr, textStatus, errorThrown){}	
		});

		return false;
	});
});

This is the function in our CFC where we will update at least one form value. I am changing the return type and return format from “plain” to “json” to demonstrate a point.

<cffunction name="ProcessFormv1" access="remote" output="false" returnType="struct" returnFormat="json">
	<cfargument name="frmData" required="yes" type="string">
	<cfset var formStruct = {} />

	<cfset formStruct = DeserializeJSON(arguments.frmData)>

	<cfset formStruct.myField1 = "I've been updated!">

	<cfreturn formStruct>
</cffunction>

I do not have ColdFusion for my portfolio web space, so you’re going to have to take my word for the following. The above has a problem. In CF8, it would eliminate leading zeroes from a text input. That seems to be resolved in CF10, but another problem remains. If you put in a considerably long number, such as 1245678901234567890123, when the application puts the form data back, that number would look like 1.245678901234568e+21, and we don’t want that!

The solution I found was the JSONUtil project: http://jsonutil.riaforge.org/. I downloaded the project and put the two CFCs into my CFC directory. With that done, here is an updated function:

<cffunction name="ProcessFormv2" access="remote" output="false" returnType="string" returnFormat="plain">
	<cfargument name="frmData" required="yes" type="string">
	<cfset var formStruct = {} />

	<cfset formStruct = DeserializeJSON(arguments.frmData)>									
	
	<cfset formStruct.myField1 = "I've been updated!">
	
	<cfset JUtil = CreateObject('component','JSONUtil')>
	<cfset formString = JUtil.serializeToJSON(formStruct,"false","true")>			

	<cfreturn formString>
</cffunction>

Other issues that one may encounter though I could not reproduce them at a later point is date formats returning with “\/” as in 11\/\08\/2017 instead of 11/08/2017. You can add the following under the assumption you would never need \/ in a string:

<cfset formString = Replace(formString,"\/","/","ALL")>

If you see a debugging message that says something like “Cannot use ‘in’ operator to…”, this might solve your problem. It happened within the jQueryField plugin.

Find this piece of code in jquery.field.js:

// if we're setting values, set them now
} else if( n in map ){

Change it to:

// if we're setting values, set them now
} else if (map.hasOwnProperty(n)) {

I used that as my solution based on what I found here: Javascript’s hasOwnProperty() Method Is More Consistent Than The IN Operator.

All of these items together allow us to pass form data back and forth as needed and is especially helpful with web application development, such as allowing validation before a form is submitted.

If you appreciate any of the work that went into making this post, please consider giving a tip to my PayPal account or supporting me on Patreon.