Simple Tool: LT and GT Replace

This page replaces “<" and ">” with “&lt;” and “&gt;”. I found myself doing it in my blog posts and thought it would be a good, simple exercise to do in my portfolio space and could be used by myself or others in the future.

Enter code here:


Updated code will display here:

The jQuery code itself doing the replacing:

<script>
(function($) {
	$("#btnReplace").click(function() {
		var str = $("#PutCodeHere").val();
		str = str.replace(/</g, "&lt;").replace(/>/g, "&gt;");
		str = str.replace( /\r?\n/g, "\r\n" );
		$("#Replaced").text(str);
	});
})( jQuery );
</script>

Source for figuring out what I needed found here:
https://stackoverflow.com/questions/20964811/replace-amp-to-lt-to-and-gt-to-gt-in-javascript

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.

Using the DataTables Plugin

My work involves showing many tables, so I use a jQuery plugin called DataTables quite a bit. For the example I want to show you, we need jQuery, jQuery UI, DataTables, and the Buttons extension for DataTables. Additionally, I will share standard custom styling I’ve done in CSS.

These are the scripts and CSS files we will be using for reference that are NOT my customization. Most links were found using the download tools on the DataTables website. The jQuery smoothness CSS file is from the Google Hosted Libraries.

<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/buttons/1.4.2/css/buttons.dataTables.min.css"/t>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/themes/smoothness/jquery-ui.css" type="text/css" media="all" /t>
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.16/css/dataTables.jqueryui.min.css" type="text/css" media="all" /t>
<script src="//code.jquery.com/jquery-1.12.4.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jszip/2.5.0/jszip.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.32/vfs_fonts.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.32/pdfmake.min.js"></script>
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.16/js/dataTables.jqueryui.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.4.2/js/dataTables.buttons.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.4.2/js/buttons.colVis.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.4.2/js/buttons.flash.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.4.2/js/buttons.html5.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.4.2/js/buttons.print.min.js"></script>

Now, the script to make the DataTable:

<script>
$(document).ready(function() {
	var table = $('#example').DataTable({
	"bJQueryUI": true,
	"bPaginate": true,
	"aLengthMenu": [[20, 50, -1], [20, 50, "All"]],
	"iDisplayLength": 20,
		buttons: [
    			{
        			extend: 'copyHtml5'
    			},
    			{
        			extend: 'excelHtml5',
        			title: 'VGCharacterst'
    			},
    			{
        			extend: 'pdfHtml5',
        			title: 'VGCharacterst'
    			},
		"print"
		]
	});

table.buttons().container().insertBefore( "#" + TableID + "_filter" );
</script>

The code starting with “var table = $(‘#example’).DataTable({“ is to indicate the example DataTable should use jQuery UI, have pages, show pages of lengths 20, 50, and All with 20 being the default length, and then use the Buttons extension. The code afterwards makes the buttons visible on the page.

Here is what the table looks like with the CSS from my own default work folder pages but not any custom DataTables styling yet:

For the ways my work uses DataTables, that is too much padding because we display more information than that, and it’s harder to separate the rows. I want it to be tighter all-around but not so tight as to have zero padding anywhere.

Here is the CSS that will change the appearance as wanted:

/* Odd stripes (including sort 1 column)*/
.dataTables_wrapper .odd {
	background-color: #fff;	
}

/* Even stripes (including sort 1 column) */
.dataTables_wrapper .even {
	background-color: #f0f0f0;
}

/* Border for table and width */
.dataTables_wrapper table {
	border-spacing: 0;
	border-collapse: collapse;	
	border: 1px solid #afafaf;
	width: 100%;	
}

/* Hover color as a light blue */
.dataTables_wrapper table tbody tr:hover td {
	background: #A4CAEF;
}

/* Show x rows width and float to the left */ 
.dataTables_length {
	width: 35%;
	float: left;
}

/* Show x rows and search box padding and bottom margin */
.dataTables_length, .dataTables_filter {
	padding: 10px 0px 0px 10px;
	margin-bottom: 7px;
}

/* Showing x of x placement (lower left with some padding) */
.dataTables_info, .dataTables_wrapper .dataTables_info {
	width: 45%;
	float: left;
	padding: 5px;	
}

/* Adds some padding to bottom for pagination buttons */
.dataTables_wrapper .ui-buttonset { padding: 10px; }

/* Removes padding on wrapper above/below table */
.dataTables_wrapper .ui-toolbar { padding: 0; }

/* Removes noticeable border for table lacking a footer */ 
table.dataTable.no-footer { border-bottom: 0; }

/* Bolds Show blank entries and showing 1 of x  in wrapper. */
.dataTables_wrapper .ui-widget-header  {
	font-weight: bold;
}

/* Floats the search filter to the left so it's in the middle-ish area instead of too far to the right */
.dataTables_wrapper .dataTables_filter {
	float: left; 
	text-align: left;
}

/* Lowers padding on table header cells  */
table.dataTable thead th {
	padding: 2px 2px 2px 4px;
}

/* Hides the sorting icon */ 
.DataTables_sort_icon { display: none; }

/* Removes bottom border along bottom of a given row, lower padding on table body cells  */
table.dataTable tbody td {
	border: 0;
	padding: 2px 2px 2px 4px;
}

/* Places buttons in upper right with some padding */
div .dt-buttons {
	margin-top: 0;
	margin-left: 10px;
	float: right;
	padding: 10px 2px 10px 4px;	
}

/* Removes spacing between buttons */
div .dt-buttons a { margin-left: -10px; }

Here is the page with the custom styling done and a screenshot below:
http://www.cathygreunkeweb.com/demos/DataTables.php

I eventually created a function upon seeing how frequently my work used DataTables. Sometimes they would be paginated, and sometimes not, and sometimes I wanted a custom filename, but using buttons*, jQuery UI, and having a preferred length were common.

My function, a little modified for the example:

<script>
	var StandardDT = function(TableID,bPaginate,FileName) {
		
		bPaginate = (typeof bPaginate === "undefined") ? true : bPaginate;
		FileName = (typeof FileName === "undefined") ? "" : FileName;
		
		var oTable= $("#" + TableID + "").DataTable({ 
			"bJQueryUI": true,
			"bPaginate": bPaginate,
			"aLengthMenu": [[20, 50, -1], [20, 50, "All"]],
			"iDisplayLength": 20,
		        buttons: [
		            {
	        	        extend: 'copyHtml5'
		            },		
		            {
	        	        extend: 'excelHtml5',
	                	title: 'FileName'
		            },
		            {
	        	        extend: 'pdfHtml5',
	                	title: 'FileName'
		            },
				"print"
	        ]
		});

		oTable.buttons().container().insertBefore( "#" + TableID + "_filter" );
	}
</script>

Then in a script placed after the table is created:

<script>
$(document).ready(function() {
	StandardDT("example",true,"VGCharacters");
});
</script>

*Buttons – Much of my work uses a retired extension called Table Tools that do a similar thing, shows buttons allowing copy/export/print. The code was written some years before the Buttons extension used here existed. In the interest of showing an active extension, I have learned and shown modified work here.

Using a JSON string prepared in ColdFusion for Autocomplete use in jQuery

The below post was originally written in September 2012 for my Tumblr. I still use this set of tools for auto-complete when creating questionnaires for my current employer and later used it for internal  uses to auto-fill entries in some of their tools and one of our clients for an entry form their vendors use.

The goal was to use jQuery UI’s Autocomplete widget and the source for what would fill in such entries was a query result set, namely a list of questions.

The next day, I decided that I wanted Autocomplete restricted to strings that started with what was being entered but to still be case insensitive.

The process went as follows:

-Use AJAX to call a CFC that would query the questions

-Return the list in an acceptable JSON structure for use in Javascript/jQuery.

-Place that array as the source for Autocomplete

-Set up Autocomplete to my specific requirements

Here is our basic ajax call. We make the result a variable since that given result is what we will be passing to Autocomplete.

var arrQst = $ajax({
	url: "path/Filename.cfc?method=GetQuestions"
	,async: false
	,type: 'POST'
}).responseText;

Here is our CFC function:

<cffunction
	name="GetQuestions"
	access="remote"
	returntype="string"
	returnformat="plain"
	output="false"
	hint="I return a list of questions">
	
	<cfquery name="qryQuestions" datasource="master">
		Select Question
		From tblQuestion
	</cfquery>
	
	<cfloop query="qryQuestions">
		<cfset returnStruct = StructNew() />
		<cfset returnStruct["value"] = qryQuestions.qst />
		<cfset ArrayAppend(result,returnStruct)/>
	</cfloop>
	
	<cfreturn serializeJSON(result) />

</cffunction>

The part after the query is the part of interest to us. That is what puts the results into a JSON structure that our jQuery will understand.

Here is our HTML input

<input type="text" name="inputstring" id="inputstring">

Here is our jQuery for Autocomplete:

function split( val ) {
	return val.split( /,\s*/ );
}
function extractLast( term ) {
	return split( term ).pop();
}

$("#inputstring#")
// don't navigate away from the field on tab when selecting an item
.bind( "keydown", function( event ) {
	if ( event.keyCode === $.ui.keyCode.TAB &&
			$( this ).data( "autocomplete" ).menu.active ) {
		event.preventDefault();
	}
}).autocomplete({
	minLength: 1,
	source: function(request,response) {
		var StringList = jQuery.parseJSON(arrQst);
                var matches = $.map( StringList, function(q) {
		//Check this pattern, starts with what is entered, 
                       //case insensitive
		var patt = new RegExp("^" + request.term, "i");
		//variable to hold if pattern matches
		var isMatch = patt.test(q.value);
		
		//if so return the string
		if(isMatch == true) {
			return q;
		}
	});
		response (matches);
	},
	focus: function() {
		// prevent value inserted on focus
		return false;
	},
	select: function(event, ui) {
		var terms = split( this.value );
		// remove the current input
		terms.pop();
		// add the selected item
		terms.push( ui.item.value );
		this.value = terms;
		return false;				   
	}
});

There were some extra steps that I must have researched nearly a year ago with the split and extractLast, from an older project, so I won’t be going over them. Here, the part of interest to us is what’s under source. There, we go over our array, check it against a regular expression to determine if the beginning what is being entered matches the values being checked in the array. We disregard case though. That way, if our user enters “the long…,” it will bring up any string that starts with those letters.

And voila, fantastic Autocomplete functionality, should be quite useful for increased productivity.