Thursday, November 29th, 2007

ColdFusion 8 Grid Magic

Category: Adobe, Ajax, ColdFusion

<p>Scott Bennett put up two nice postings which demonstrate how to extend ColdFusion 8′s built-in Grid control. I’ve mentioned before that CF8 uses Ext v1.0 and as such offers a ton of flexibility not generally mentioned in the CF documentation.

Grid Validation

In his first post, Scott shows how to implement validation of CFGrid data. Leveraging Ext’s validateedit event, which fires after a cell is edited but before the value is actually saved, Scott was able to include code that validated the data prior to being saved:

Now whenever the validateedit event fires, it will call the dataValidator() function. The dataValidator() function checks to see if the field that is being edited needs validation, and then validates the data if necessary. In this example, I added validation for the Expiration Date, and the numeric Sponsor ID for the coupon record. If the data fails validation an alert is thrown and the edit event is canceled(reverting the data back to it’s original value).


<html>
<head>
   <title>CFGird Custom Date Validator</title>
   <!--- import the Ext date package --->
   <cfajaximport tags="cfinput-datefield">
   <!--- create javascript function for rendering dates --->
   <script language="JavaScript" type="text/javascript">

   setDateRenderer = function(){
      mygrid = ColdFusion.Grid.getGridObject('CouponsGrid');
      cm = mygrid.getColumnModel();
      cm.setRenderer(3, Ext.util.Format.dateRenderer('m/d/Y'));
      mygrid.reconfigure(mygrid.getDataSource(),cm);
   }
   dataValidator = function(editEvent){
      //Date Field Validation

      if (editEvent.field == "EXPIRATIONDATE"){
         if (isNaN(Date.parse(editEvent.value))){
            alert("Please enter a date in this field.");
            editEvent.cancel = true;
         }
         else {

            data = new Date(Date.parse(editEvent.value));
            editEvent.value = data.dateFormat("m/d/Y");
         }
      }
      //Numeric Field Validation

      if (editEvent.field == "SPONSORID"){

         if (isNaN(editEvent.value)){
            alert("Please enter a numeric value in this field.");
            editEvent.cancel = true;
         }
      }
   }
   addValidator = function(){
      mygrid = ColdFusion.Grid.getGridObject('CouponsGrid');

      mygrid.on('validateedit',dataValidator);
   }
   init = function(){
      setDateRenderer();
      addValidator();
   }
   </script>
</head>

<body>
<!--- Set up the Grid --->
<cfform id="CouponForm" name="CouponForm">
<cfgrid name="CouponsGrid"
format="html"

pagesize="10"
striperows="yes"
selectmode="edit"
bind="cfc:coupons.getCoupons({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})"
onchange="cfc:coupons.editCoupon({cfgridaction},{cfgridrow},{cfgridchanged})">

<cfgridcolumn name="Couponid" display="false" />
<cfgridcolumn name="SPONSORID" header="Sponsor" width="100"/>

<cfgridcolumn name="COUPON" header="Coupon" width="100"/>
<cfgridcolumn name="EXPIRATIONDATE" header="Exp Date" width="200"/>

</cfgrid>
</cfform>

<!--- use AjaxOnLoad to call the init() function --->
<cfset ajaxOnLoad("init")>
</body>
</html>

Custom Date Renderer

In his second post, Scott again takes advantage of Ext’s capability and shows how to create a custom date renderer:

One of the coolest things about the ColdFusion 8 implementation of the CFGrid tag is that you can do a lot of customization, if you know your way around the Ext objects. I have found several blog entries about using custom renderers with the CFGrid tag. However, could not find a working example of one for date fields, so I decided to build one.

CouponForm.cfm


<html>
<head>
   <title>Custom Date Renderer</title>
   <!--- import the Ext date package --->
   <script src="/CFIDE/scripts/ajax/ext/package/date.js" type="text/javascript"></script>

   <!--- create javascript function for rendering dates --->
   <script language="JavaScript" type="text/javascript">
   setDateRenderer = function(){
      mygrid = ColdFusion.Grid.getGridObject('CouponsGrid');
      cm = mygrid.getColumnModel();
      cm.setRenderer(3, Ext.util.Format.dateRenderer('m/d/Y'));

      mygrid.reconfigure(mygrid.getDataSource(),cm);
   }
   </script>
</head>

<body>
<!--- Set up the Grid --->
<cfform id="CouponForm" name="CouponForm">

<cfgrid name="CouponsGrid"
format="html"
pagesize="10"
striperows="yes"
selectmode="edit"

bind="cfc:coupons.getCoupons({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})"
onchange="cfc:coupons.editCoupon({cfgridaction},{cfgridrow},{cfgridchanged})">
<cfgridcolumn name="Couponid" display="false" />

<cfgridcolumn name="SPONSORID" header="Sponsor" width="100"/>
<cfgridcolumn name="COUPON" header="Coupon" width="100"/>

<cfgridcolumn name="EXPIRATIONDATE" header="Exp Date" width="200"/>
</cfgrid>
</cfform>

<!--- use AjaxOnLoad to set the date renderer --->
<cfset ajaxOnLoad("setDateRenderer")>
</body>
</html>

</html>

The secret sauce in this code is the following line:

cm.setRenderer(3, Ext.util.Format.dateRenderer(‘m/d/Y’));

That’s the built-in Ext method that allows you to define your custom date renderer. Again, this is not something that’s actively promoted by Adobe, most likely since they’re trying to abstract the intricacies of the Ext framework via a cozy HTML-centric syntax. This, in my opinion, is not a bad thing as it eases new developers into client-side development while still allowing experienced developers to extend their apps via the framework’s actual API.

Related Content:

Posted by Rey Bango at 7:30 am
5 Comments

+++--
3.3 rating from 46 votes

5 Comments »

Comments feed TrackBack URI

As a CF developer that loves JS, I have a hard time with the built-in custom-tag like HTML/JS wrappers that come in CF. I guess its because I understand whats under the hood, and I know that I can do the same things more cleanly, and with a higher level of control then what you can handle with the built in system. I mean, having the tags as short-cuts is nice and all, but 90% of the time, if you want to do anything really useful with them, you have to understand JS anyway in order to write the custom code. If I already know JS, and understand Ext well enough to customize the components, why wouldn’t I just write it myself?

Comment by Jon Hartmann — November 29, 2007

@Jon – I agree with you, to a point. Remember that ColdFusion ‘Makes the hard things easy’. A less experienced developer can quickly piece together a nice, functional application. A more experienced developer can, using these new features, quickly prototype an application which can later be expanded upon and improved by using the Ext library directly, while maintaining the same look and feel. My client may want only what’s been generated by CF8, and nothing further, and have a limited budget. Or, they may say ‘that looks great, but I also want it to do this,’ at which point I can bill them for further custom development with Ext.

Comment by Cutter — November 29, 2007

I posted an entry on cell renders a while back on my blog http://www.garyrgilbert.com/blog/index.cfm/2007/8/24/CFGRID-Cell-Renderer-Revisited

Be aware that the date package only works for US formatted dates (29.11.2007 fails).

Comment by Gary Gilbert — November 29, 2007

@Cutter – Well said. It is definitely a lot easier to start with the cfgrid tag as a base, and then just add a few quick JavaScript functions to customize the grid as necessary. Additionally I had never used the Ext objects before CF8 came out, so it would have taken me a lot longer figure out how to build an entire grid functionality from scratch.

@Gary – Good point, the nice thing is that you can just write your own function to format the date however you like, so you could make a “euroDateRenderer” function that formats the date string the way you need it to and then change the line:

cm.setRenderer(3, Ext.util.Format.dateRenderer(’m/d/Y’));

to

cm.setRenderer(3, euroDateRenderer);

Comment by Scott Bennett — November 29, 2007

CF FTW

Comment by starkraving — November 30, 2007

Leave a comment

You must be logged in to post a comment.