Categories
ColdFusion HTML-JS-CSS Tech

Dynamic Form Templates with CFInclude



ColdFusion is a pretty powerful language when it comes to managing all your server / enterprise resources, but it is also useful to manipulate user interfaces.

In this post, we speak about using the CFInclude tag to build intuitive user experiences.

To start with, here is our problem. We had multiple pages in a website, and all of them were used to capture data. The issue was, none of the fields captured were finite. We had to capture (into a database) fields that were different across forms. Creating a table for each form was impractical – so it had to be into a single table. To reframe in a more technical wording, the problem is to insert key value pairs from multiple web forms, into a common database. A fairly simple problem, but the expectation was also to ensure a good user-experience. Here’s an illustration of how we went about solving it.

Like we said, all data were to be inserted into a common database table. So we created a database table that had the following fields,

recordID (auto incremented integer)
webpageIdentifer (string)
key (string)
value (string)

The fields are fairly self descriptive. The first, is a auto incremented primary key. The second is a reference to the webpage from which the information is being inserted. The third and fourth are fields expected to hold the key value pairs – the data captured via the web forms we spoke about.

To proceed, we created files with the following structure.

mainPage.cfm
savePage.cfm
templates/template1.cfm
templates/template2.cfm

mainPage.cfm is our landing page. Since the intent was to maintain a good user experience, we went about designing eye pleasant forms with foundation, that were optimized in CSS and JavaScript, to hold appropriate, range-validated values, context based visibility of controls, etc. In our case, template1.cfm and template2.cfm are the two context specific templates that are expected to collect our context based key, value pairs. Here’s a representation of the two templates.

template1.cfm
A simple HTML page that defines three free form text fields.


<label>Install Location
    <input name="install_location" type="text" placeholder="C:\\"></input>
</label>
<label>Install Platform 
    <input name="platform" type="text" placeholder="Windows"></input>
</label>
<label>Install as user
    <input name="user" type="text" placeholder="root"></input>
</label>

template2.cfm
A HTML page that defines a set of dropdowns who’s visibility is updated based on the value of the first drop down.


<script language="javascript">
 
    $(document).on('change','[name="deployment"]',function(){
         
        switch($('[name="deployment"]').val()) {
            case "webserver":
                $('[name="webserver"]').show(); 
                $('[name="j2eeserver"]').hide();
                $('[name="standaloneOptions"]').hide();
                break;
                 
            case "j2eeserver":
                $('[name="webserver"]').hide(); 
                $('[name="j2eeserver"]').show();
                $('[name="standaloneOptions"]').hide();
                break;
                 
            case "standalone":
                $('[name="standaloneOptions"]').show();
                $('[name="webserver"]').hide(); 
                $('[name="j2eeserver"]').hide();
                break;
                 
            default:
                $('[name="webserver"]').hide(); 
                $('[name="j2eeserver"]').hide(); 
                $('[name="standaloneOptions"]').hide();
                break;
            }
        });
 
</script>
 
<select name="deployment">
    <option value="na">Select deployment server</option>
    <option value="standalone">Standalone</option>      
    <option value="webserver">Web Server</option>
    <option value="j2eeserver">Application Server</option>
</select>
<select name="webserver">
    <option value="na">Select web server</option>
    <option value="apache">Apache</option>
    <option value="iis">IIS</option>
</select>
<select name="j2eeserver">
    <option value="na">Select J2EE server</option>
    <option value="tomcat">Apache Tomcat</option>
    <option value="wildfly">WildFly</option>
    <option value="weblogic">Weblogic</option>
    <option value="eap">EAP</option>
</select>
<div name="standaloneOptions" class="large-12 columns">
    <label>Identifier
        <input name="standalone-identifier" type="text" placeholder="Standalone"></input>
    </label>
</div>

Now, our mainPage.cfm expects a query parameter that defines whether template1.cfm, or template2.cfm, is required to be loaded. It also defines a form control, which then inserts the contents of the template through CFInclude. Here’s the code. In order to keep the code simple, no error handling scenarios exist.

mainPage.cfm


<script language="javascript">
 
    $('#webpageData').submit(function(event){
 
        var url = 'savePage.cfm';
        var serializedData = form.serialize();
         
        $.post(url,serializedData,function(data,status){
                 
            if(data.length > 0) {
                var returnObject = jQuery.parseJSON(data);
                if(returnObject.Success == true) {
                    location.reload();
                }
            }
        });
        return false;
    });
</script>
 
<cfset templateName = "template1.cfm">
<cfif StructKeyExists(URL, 'webpage')>
    <cfif FileExists(ExpandPath("template/#URL.webpage#.cfm"))>
        <cfset templateName = #URL.webpage#>
        <br><br>
    </cfif>
</cfif>
 
<form id="webpageData">
 
    <cfinclude template="template/#templateName#.cfm">
     
    <input type="hidden" name="meta_webpageIdentifier" value="<cfoutput>#templateName#</cfoutput>">
    <input type="submit" class="button tiny success" value="Save" style="float:right">
</form>

What we have here is a main page that is queried with the name of the form that needs to be loaded, while defaulting to template1.cfm. All form content can be broken down to a key and value – thanks to the Form Submit action that holds the form-data. Our savePage.cfm then just captures all the form-data, and inserts them into our database table. Notice mainPage.cfm also has a hidden form element, meta_webpageIdentifier. This information is also appropriately inserted into the database. Key’s with a prefix such as ‘meta_’ can be skipped during insert with a selective search.

savePage.cfm


<cfset keyList="">
<cfloop LIST="#FORM.FIELDNAMES#" index="item">
    <cfif FindNoCase("meta_",item) neq 1>
        <cfset keyList=ListAppend(keyList,item)>
    </cfif>
</cfloop>
 
<cfquery name="deleteKeyValuePairs" datasource="#datasource#">
    delete from keyValueStore where webpageIdentifer = #FORM.meta_webpageIdentifier#
</cfquery>
 
<cfloop list="#keyList#" index="item">
     
<cfset value=#FORM[item]#>
    <cfquery name="addNewKeyValuePairs" datasource="#datasource#">
        insert into keyValueStore(webpageIdentifer, `Key`, `Value`) values (#FORM.meta_webpageIdentifier#, "#item#","#value#")
    </cfquery>
 
</cfloop>

And that’s how we maintain a common database for a set of inputs taken in from completely different user interfaces – with zero lines of code for manipulating data, or for processing input data before database insertion.

A Log Analyzer with the ELK Stack, Nginx and Docker
ColdFusion API Manager at CFSummit 2018

By Immanuel Noel

A techie at heart. Works with Adobe at Bangalore, India. Currently do DevOps. Been a part of the ColdFusion Engineering, Flash Runtime Engineering, Flash Builder Engineering teams in the past. Was a Flash Platform Evangelist, evangelizing the Adobe Flex platform. Spoke at numerous ColdFusion / Flash and Flex tech conferences. This blog is a collection of some of my strides with technology.

More on me on the home page

Leave a Reply

Your email address will not be published. Required fields are marked *