Unobtrusive Table Sort Solution

Looking for a good dynamic table sorting solution? We have been playing with a few out there including spry and well we think we have found a goodie.

We thought we would take a sec to explain how we integrated it into an app. Whats great about this implementation is it is totally unobtrusive and could be implemented site-wide with ease.

We included the two javascript files that you can downloaded at the bottom of http://www.frequency-decoder.com/ blog entry.

The first script can run without the second script if you don't require page numbering however i would highly recommend it.

<script type="text/javascript" src="js/tablesort.js"></script>
<script type="text/javascript" src="js/pageNumber.js"></script>

Now simply create your table and its all about the class, we have tested with more than one table and it was absolutely fine..

<table id="anotherTable" cellpadding="0" cellspacing="0" class="sortable-onload-3-reverse rowstyle-alternative no-arrow paginate-7">

Its all about the class which its pretty clever. To breakdown what we have worked out each parameter means

  • sortable(pretty clear) - onload-3-reverse (sort column three in reverse)
  • rowstyle-alternative (pretty clear)
  • paginate-7 (how many records to show on a page)

Now simply create the rest of your table defining which columns you want to sort by

<thead>
         <tr>
            <th class="sortable">Name</th>
            <th class="sortable">Level</th>
            <th class="sortable">Username/Email</th>
            <th class="sortable">Password</th>
            <th>Edit</th>
            <th>Delete</th>
         </tr>
      </thead>
    <tbody>   
      <cfloop query="qgetUser">
         <tr>
            <td>#qgetUser.lastname#, #qgetUser.FirstName#</td>
            <td>#oU.getLevel(qgetUser.level)#</td>
            <td>#qgetUser.email#</td>
            <td>#qgetUser.password#</td>
            <td><a href="?edit=#qgetUser.uid#">Edit</a></td>
            <td><a href="?deleteUser=#qgetUser.uid#">Delete</a></td>
         </tr>
      </cfloop>
   </tbody>
   </table>

We have done some load testing and as the author explains there are a number of things that will slow this down including having ALOT of records. However the wait was totally acceptable with a thousand or so records. Hopes this helps and if all goes well and we can find sometime look forward to an update to our datagrid solution.

Spry - First Experience

Got a neat little note tracking system to develop and thought that the spry framework could be used to do the view layer. So here is my First Spry experience.

What I am doing is fairly basic, pretty much recieving a recordset out of a cfc into a proxy page then displaying a dynamic table through a custom tag.

This example goes through the process from a query to displaying the table in a custom tag.

So i changed my getNotes() function to returntype="xml" and by using Ray's toxml() i did the following to my recordset

<cfset toXML = createObject("component", "****.cfc.utility")>
<cfset xmlQuery = toXML.queryToXML(qGetNote, "notes", "note")>
<cfreturn xmlQuery />

I now set up a proxy page to hit the cfc and return the xml object

<cfsetting showdebugoutput="false">
<cfscript>
oNM = createObject("component","***.cfc.notemanager");
   xmlNotes = oNM.getNotes(url.itemId, url.typeid);
</cfscript>
<cfcontent reset="true" type="text/xml"><cfoutput>#xmlNotes#</cfoutput>

And after calling the spry js i then called my proxy page.

<script type="text/javascript" src="/assets/spryFramework/js/xpath.js"></script>
<script type="text/javascript" src="/assets/spryFramework/js/SpryData.js"></script>
<script type="text/javascript">
var dsNotes = new Spry.Data.XMLDataSet("noteProxy.cfm?ItemId=#attributes.itemId#&typeid=#attributes.typeId#", "notes/note");
</script>

Now that the spry dataset was in all i had to do was display it.

This is the really neat part of spry

create a spry region to display your data

<div spry:region="dsNotes">
// table goes here </div>

Then create your table

<table border="1" id="note">
   <tr>
      <th scope="col">datecreated</th>
      <th scope="col">Description</th>
      <th scope="col">Method</th>
      <th scope="col">User</th>
      

   </tr>

On columns that you want to be able to sort add the following

onclick="dsNotes.sort('DTCREATED');
// for example <th scope="col" onclick="dsNotes.sort('USERID');">
User</th>

Then set up your spry results

<tr>
<td>{DTCREATED}</td>
<td>{NOTEDESCRIPTION}</td>
<td>{METHOD}</td>
<td>{USERID}</td>
</tr>

this should return the first record and very much like coldfusion all you need to do is define where you want to loop like this

<tr spry:repeat="dsNotes">
      <td>{DTCREATED}</td>
      <td>{NOTEDESCRIPTION}</td>
      <td>{METHOD}</td>
      <td>{USERID}</td>
   </tr>

TIP - its case senstive!!! and rays toxml function makes everything Upper Case.

So now when i want to include my note table all i have to do is include the following at the bottom of any item page and up comes a spry table

<ui:notes itemid="#request.input.id#" typeid="1" username="#ou.loginname#"/>

Resources I used to getting it working inside our system were

  • Dynamic Table Tutorial on Adobe Labs
  • Ray's toXML() function and widsom
  • Large Amount of Spry Resource

  • BlogCFC and GoogieSpell Intergration Explained

    In the last post we created a package to install googiespell into your blogcfc and now we would like to explain how we did this.

    install the attached zip file into your site root.

    wwwroot/googiespell

    and where you want to add the spell checking functionality include the following .js and css pages

    <script type="text/javascript" src="/googiespell/AmiJS.js"></script>
    <script type="text/javascript" src="/googiespell/googiespell.js"></script>
    <script type="text/javascript" src="/googiespell/cookiesupport.js"></script>
    <link href="/googiespell/googiespell.css" rel="stylesheet" type="text/css" />

    In blogcfc there are two nice places to add the spell checking functionality

    admin entry editor - /admin/entry.cfm
    comments /addcomments.cfm

    now in this example we will add it to /admin/entry.cfm look for the textarea that holds the body and add an ID="" to it so it looks like

    <textarea name="body" class="txtArea" id="body">#form.body#</textarea>

    and then add the javascript code needed to load the spell checker

    <script>
    var googie1 = new GoogieSpell("/googiespell/", "http://#cgi.HTTP_HOST#/googiespell/googleapi.cfm?");
    googie1.decorateTextarea("body");
    </script>

    Now if the googiespell directory is in your root you should have no worries however if you have moved it then you will have to ensure you fix it up here. Also at the moment we have it pointing to cgi.http_host however this could be static like

    This is all you have to do to getting it working with coldfusion we have just used this amazing blog as an example. There are, as explained in previous blog entries modifications to the release version of googiespell (3.78) and you should visit Orangoo Labs Licence for GoogieSpell to ensure you comply with the license agreement.

    Hope you find this useful.

    BlogCFC and GoogieSpell

    Attached is a zip file that integrates GoogieSpell into Ray's BlogCfC

    As explained in previous posts we have had to modify the actual release code of googiespell 3.78 to get it running with coldfusion, due to the way it was sending the form scope.

    The only actual change in the blogcfc code is the addition of 3 javascripts and 1 css in the entry.cfm page.

    The other change you may have to make is relative to where the googleapi.cfm is sitting. currently I have it sitting in the root and pointing to

    http://#cgi.HTTP_HOST#/googiespell/googleapi.cfm?

    Yet you may need to change this if it is incorrect.

    For an example of the spell checking working with blogcfc add a comment to this blog entry as we have integrated it here for demo purposes.

    Update to Spelling Integration

    After testing out the spelling implementation we found that we were having issues with html tags and other unique characters. We couldn't even get it to send to our action page.

    So we did some research and decided to encode the text string in the javascript and this worked nicely.

    So we replaced the

    GoogieSpell.createXMLReq = function (text) {
    return 'textstring=' + text;
    }

    with

    GoogieSpell.createXMLReq = function (text) {
    return 'textstring=' + encodeURIComponent(text);
    }

    And had success. A lot of our blog entries have code and interesting characters and we have not had any issues so far but of course we will keep you posted on any other issues we have.

    If you would like to research more of the capabilities of the encodeURIComponent() function this page Comparing escape(), encodeURI(), and encodeURIComponent() was very useful. It certainly saved us here!

    Posting a Form with Ajax.

    Expanding on our current xmlhttp request function. We wanted the flexibility to send not only via the url scope but also the form.

    So to expand on our function we had to do the following.

    set up our parameters we want to send

    var parameters = "txtarea1=" + encodeURI( document.getElementById("txtarea1").value ) + "&txtarea2=" + encodeURI(document.getElementById("txtarea2").value );

    Set up our headers

    xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xmlhttp.setRequestHeader("Content-length", parameters.length);

    And then send the paramaters

    xmlhttp.send(parameters);

    To test your results set up a cfdump(form) or an output to file on the action page and you should be able to see the form parameters you sent.

    Check this page out as another example, this example also has some neat error handling in it.

    Integrating Spell Checking into your Coldfusion Applications

    While the web becomes more popular and easier for publishing content it doesn't mean we are getting better at spelling.

    During our quest for a spelling solution, we at Redballoon found a very nice ajax plugin that allows you to add a spell checker into any textarea in your application.

    Introducing GoogieSpell.

    What is so brilliant about this plug in is its "gmail" like functionality. While this plug in appears to be out of the box it has one very major limitation.

    You can't directly run this script online (this is a browser security issue). To solve this you can have a simple "local" sever (i.e. a server that you can send requests to) running that sends requests to Google.

    While the author provides solutions for php/perl/asp there was not yet a coldfusion solution available on the site.

    So we sat down and developed a coldfusion implementation that slides nicely into our labs blog (Ray Camden's Blog CFC).

    Here is the solution we came up with.

    Once you have called in the 3 javascripts and the 1 css just put an 'id' on your textarea and instead of calling this that is straight out of the demo.html

    var googie1 = new GoogieSpell("googiespell/", "https://www.google.com/tbproxy/spell?lang=");
    googie1.decorateTextarea("ta1");

    call this

    var googie1 = new GoogieSpell("/googiespell/", "http://#cgi.HTTP_HOST#/googiespell/googleapi.cfm?");
    googie1.decorateTextarea("ta1");

    So essentially all we are doing is calling our coldfusion page instead of the google page directly.

    Now, we did have to change one thing in the core "googiespell.js" as it was not passing the form scope correctly across to our coldfusion page.

    We changed the createXMLReq from

    GoogieSpell.createXMLReq = function (text) { long function }

    to

    GoogieSpell.createXMLReq = function (text) {
    return 'textstring=' + text;
    }

    And then all we have to do is the http call on the coldfusion page "googleapi.cfm?"

    Which you can copy and paste from below

    <cfsetting showdebugoutput="false">
    <cfsavecontent variable="xmlpacket"><?xml version="1.0"?><spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1"><cfoutput>#tostring(form.textstring)#</cfoutput></spellrequest></cfsavecontent>
    <cfhttp method="post" url="https://www.google.com/tbproxy/spell?lang=en" result="xmlresult">
       <cfhttpparam value="#tostring(xmlpacket)#" type="body">
    </cfhttp>
    <cfcontent reset="true" type="text/xml"><cfoutput>#xmlresult.filecontent#</cfoutput>

    There were many ways we debugged what was going on and one of the most useful ways was using a firefox extension "live headers". This allowed us to log and watch LIVE what each page was passing to each other.

    If you would like to know more regarding this project or how to implement it into your application please feel free to leave a comment and we will do our best to help out.

    Play with xmlhttp and Coldfusion

    This is our implementation of xmlhttp so far... but we are certainly looking at ways to improve it.

    <form name="formName">
    <input name="inputFieldYourPassing" type="text" value="Frogs">
    <input name="inputName" type="button" onclick="javascript:funkyfunction();" value="Hit Play">
    </form>
    <div id="divName">
    </div>
    This is the form that we are passing to the function which should be in the of the page.
    function funkyfunction() {
    call the function
    document.getElementById('divName').innerHTML = 'Processing Request';
    Tell your user friend you are doing something...
    var Current = "actionPage.cfm?varYoursPassign=" + document.formName.inputFieldYourPassing.value;
    What you are doing here is setting the action page to hit with the variables. You can send any document objects by passing them through the function like
    document.formName.whatever.value
    The best way to test to see if everything thing is working, is to put
    <cfdump var="#url#>
    on your action page. Now open up your Xmlhttp Connection
    xmlhttp.open("GET", Current, true);
    xmlhttp.onreadystatechange=function() {
    if (xmlhttp.readyState==4) {
    Now 4 is "Successful Connection" and if you would like to put a few cushions incase the connection was not as success as you would have liked then this is the place to do it. However if all is well you can pass through whatever the action page outputed into your div
    document.getElementById('divName').innerHTML = xmlhttp.responseText;
    Otherwise nothing will happen and most likley one of your variables are spelt incorrectly, you can test that by going into the javascript debug menu in FireFox.
    }
    }
    xmlhttp.send(null)   
    }

    Hope this helps and we have certainly extensively used this, But as we said we are certainly looking at ways to make this better.

    Getting FckEditor to Fcking Play With Ajax

    After Upgrading Fck Editor to 2.3 we started to look at ways for it to interact with our xmlhttp.open function.

    The idea was to onclick a function that would submit the editors content without refreshing the page then clear the editors area.

    With the inbuilt javascript api library we were able to do the following.

    var oEditor = FCKeditorAPI.GetInstance('template');
    - create the object

    oEditor.GetXHTML()
    -accesses the live content of the obejct

    oEditor.SetHTML('');
    -clears the object or

    oEditor.SetHTML(xmlhttp.responseText);
    -to post the content from the xmlhttp transfer to the live object