Wednesday, March 10, 2010    
Home My Books Blog ColdFusion About Me Back    

Calendar
<< Jun 2007 >>
S M T W T F S
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
             

Search

Categories
 • Acrobat (3) [RSS]
 • Adobe (88) [RSS]
 • AdobeMAX06 (45) [RSS]
 • AdobeMAX07 (59) [RSS]
 • AdobeMAX08 (66) [RSS]
 • AdobeMAX09 (39) [RSS]
 • AdobeMAX10 (1) [RSS]
 • AIR (219) [RSS]
 • Appearances (191) [RSS]
 • Books (72) [RSS]
 • CFEclipse (15) [RSS]
 • ColdFusion (1378) [RSS]
 • Data Services (34) [RSS]
 • Fish Tank (4) [RSS]
 • Flash (196) [RSS]
 • Flex (496) [RSS]
 • Home Automation (4) [RSS]
 • Jobs (116) [RSS]
 • JRun (14) [RSS]
 • Labs (43) [RSS]
 • LiveCycle (34) [RSS]
 • MAX (232) [RSS]
 • Mobile (119) [RSS]
 • Regular Expressions (17) [RSS]
 • RIA (21) [RSS]
 • SQL (40) [RSS]
 • Stuff (535) [RSS]
 • Tips (CF Studio) (80) [RSS]
 • Tips (CF) (795) [RSS]
 • Tips (Dreamweaver) (91) [RSS]
 • Tips (Flex Builder) (2) [RSS]
 • Using CF (162) [RSS]

Other BLOGs
 • Charlie Arehart
 • Lee Brimelow
 • Ray Camden
 • Christophe Coenraets
 • Sean Corfield
 • Mihai Corlan
 • Cornel Creanga
 • Mark Doherty
 • John Dowdell
 • Danny Dura
 • Enrique Duvos
 • Steven Erat
 • Kevin Hoyt
 • Serge Jespers
 • Adam Lehman
 • Duane Nickull
 • Miti Pricope
 • Andrew Shorten
 • Ryan Stewart
 • James Ward
 • Greg Wilson
 • Full As A Goog

RSS Feeds
 • Feed
 • Subscribe

Join my mailing list and find out about new books and other topics of interest.

Thoughts, ideas, tips, musings, and pontifications (not necessarily in that order) by Ben Forta ...
NOTE: This is my personal blog, and the opinions and statements voiced here are my own.

Viewing By Entry / Main
June 25, 2007

ColdFusion Ajax Tutorial 6: Editable Data Grids

Previously we looked at the new ColdFusion 8 data grid and how to populate that control using asynchronous calls back to a ColdFusion Component. In that example the CFC contained a single method that returned a page of data as requested by the data grid.

Like the previous incarnations of <CFGRID>, the new Ajax enabled HTML grid allows data to be updated right within the grid. When the <CFGRID> is used in edit mode, column values may be edited as needed, and rows may be deleted. Unfortunately, the current implementation of the HTML <CFGRID> does not support inserting new rows. This is a pretty serious limitation, and one that we'll hopefully address in the future - for now you'll need to use another form to add new rows.

You will recall that <CFGRID> requests data as needed by making calls to a CFC method specified in the bind attribute. To process edits a second CFC method is needed, and it must be passed to the onchange attribute. Here is a modified <CFGRID> that supports data editing:

<cfwindow initshow="true" center="true"
            width="430" height="340" title="Artists">


<cfform>
    <cfgrid name="artists"
            format="html"
            pagesize="10"
            striperows="yes"
            selectmode="edit"
            delete="yes"
            bind="cfc:artists.getArtists({cfgridpage},
                                        {cfgridpagesize},
                                        {cfgridsortcolumn},
                                        {cfgridsortdirection})"

            onchange="cfc:artists.editArtist({cfgridaction},
                                            {cfgridrow},
                                            {cfgridchanged})"
>

        <cfgridcolumn name="is" display="false" />
        <cfgridcolumn name="lastname" header="Last Name" width="100"/>
        <cfgridcolumn name="firstname" header="First Name" width="100"/>
        <cfgridcolumn name="email" header="E-Mail" width="200"/>
    </cfgrid>
</cfform>

</cfwindow>

There are three changes in this <CFGRID> (compared to the grid created previously). First of all, selectmode="edit" puts the data grid in edit mode. This allows editing, but not deleting. To allow rows to be deleted, delete="yes" is also specified. And finally, a CFC method is specified in the onchange attribute. When invoked (upon an edit or a delete) three arguments will be passed, the action (U for update or D for delete), the row being changed, and the changes (only populated for updates, and not for deletes).

The specified CFC has to accept these three arguments, and returns no data. Within the CFC you can use <CFQUERY> tags (or perform any other operations) to actually perform the updates. Here's an example:

<!--- Edit an artist --->
    <cffunction name="editArtist" access="remote">
        <cfargument name="gridaction" type="string" required="yes">
        <cfargument name="gridrow" type="struct" required="yes">
        <cfargument name="gridchanged" type="struct" required="yes">

        <!--- Local variables --->
        <cfset var colname="">
        <cfset var value="">

        <!--- Process gridaction --->
        <cfswitch expression="#ARGUMENTS.gridaction#">
            <!--- Process updates --->
            <cfcase value="U">
                <!--- Get column name and value --->
                <cfset colname=StructKeyList(ARGUMENTS.gridchanged)>
                <cfset value=ARGUMENTS.gridchanged[colname]>
                <!--- Perform actual update --->
                <cfquery datasource="#THIS.dsn#">
                UPDATE artists
                SET #colname# = '#value#'
                WHERE artistid = #ARGUMENTS.gridrow.artistid#
                </cfquery>
            </cfcase>
            <!--- Process deletes --->
            <cfcase value="D">
                <!--- Perform actual delete --->
                <cfquery datasource="#THIS.dsn#">
                DELETE FROM artists
                where artistid = #ARGUMENTS.gridrow.artistid#
                </cfquery>
            </cfcase>
        </cfswitch>
    </cffunction>

The code uses a <CFSWITCH> to process a gridaction of U (update) or D (delete). For updates, argument gridchanged will be a structure containing an element for each column changed, the element name is the column name and the element value is the new value. Each column is updated individually, if a user makes three edits to the same row in the data grid the this method will be called three times, once for each row. As such, for updates, gridchanged only ever contains a single element, and so the code extracts the column name and value and saves them to local variables. These variables are then used in a <CFQUERY> to perform the actual update, using the primary key in the passed row (ARGUMENTS.gridrow) for the SQL WHERE clause. Deletes are processed similarly, with only the primary key needed.

Here is the complete artists.cfc, with both the bind and onchange methods:

<cfcomponent output="false">


    <cfset THIS.dsn="cfartgallery">


    <!--- Get artists --->
    <cffunction name="getArtists" access="remote" returntype="struct">
        <cfargument name="page" type="numeric" required="yes">
        <cfargument name="pageSize" type="numeric" required="yes">
        <cfargument name="gridsortcolumn" type="string" required="no" default="">
        <cfargument name="gridsortdir" type="string" required="no" default="">

        <!--- Local variables --->
        <cfset var artists="">

        <!--- Get data --->
        <cfquery name="artists" datasource="#THIS.dsn#">
        SELECT artistid, lastname, firstname, email
        FROM artists
        <cfif ARGUMENTS.gridsortcolumn NEQ ""
            and ARGUMENTS.gridsortdir NEQ "">

            ORDER BY #ARGUMENTS.gridsortcolumn# #ARGUMENTS.gridsortdir#
        </cfif>
        </cfquery>

        <!--- And return it as a grid structure --->
        <cfreturn QueryConvertForGrid(artists,
                            ARGUMENTS.page,
                            ARGUMENTS.pageSize)>

    </cffunction>


    <!--- Edit an artist --->
    <cffunction name="editArtist" access="remote">
        <cfargument name="gridaction" type="string" required="yes">
        <cfargument name="gridrow" type="struct" required="yes">
        <cfargument name="gridchanged" type="struct" required="yes">

        <!--- Local variables --->
        <cfset var colname="">
        <cfset var value="">

        <!--- Process gridaction --->
        <cfswitch expression="#ARGUMENTS.gridaction#">
            <!--- Process updates --->
            <cfcase value="U">
                <!--- Get column name and value --->
                <cfset colname=StructKeyList(ARGUMENTS.gridchanged)>
                <cfset value=ARGUMENTS.gridchanged[colname]>
                <!--- Perform actual update --->
                <cfquery datasource="#THIS.dsn#">
                UPDATE artists
                SET #colname# = '#value#'
                WHERE artistid = #ARGUMENTS.gridrow.artistid#
                </cfquery>
            </cfcase>
            <!--- Process deletes --->
            <cfcase value="D">
                <!--- Perform actual delete --->
                <cfquery datasource="#THIS.dsn#">
                DELETE FROM artists
                WHERE artistid = #ARGUMENTS.gridrow.artistid#
                </cfquery>
            </cfcase>
        </cfswitch>
    </cffunction>


</cfcomponent>

We'll look at additional <CFGRID> examples in the future.

TrackBacks
There are no trackbacks for this entry.

No trackback URL. Trackbacks are only allowed via interactive form.

Comments
As always your blog was very helpful. I am running CF9 and LOVE the new features for cfgrid! There isn't much out there regarding cfgrid for Coldfusion 9 yet....wondering if it is possible to add log in/log out capability within cfgrid using CF9?
# Posted By Elizabeth | 12/16/09 7:07 PM
How can I update a checkbox? I have a cfgridcolumn set to type= boolean, but the component gives me error when update...
# Posted By Francesco | 12/21/09 7:45 AM
How to update cfgridcolumn type boolean?
# Posted By Francesco | 12/21/09 7:46 AM
Indeed, yes: how about checkboxes?

The only way I've been able to get a boolean field to display a checkbox is to make the grid editable, and even then it still displays "true" or "false" until one clicks on the cell twice.

Am I doing something wrong, or is this a bug?

--
Adam
# Posted By Adam Cameron | 2/17/10 2:28 PM

  © Copyright 1997-2009 Ben Forta, All Rights Reserved