CFGRID Cell Renderer - ComboBox (Select)

Posted By : todd sharp Posted At : June 12, 2006 8:32 PM Posted In: Flash Forms, ActionScript, ColdFusion

23

As promised in my last post, here is an example of creating a custom cell renderer for a select in a cfgrid. To be fair, the code isn't my own (though I can't seem to find where I originally found it. This example is purely to show that the custom renderer can be applied to a cfgrid within a Flash Form and can easily be customized to meet your individual needs.

The dataprovider is hardcoded in this example, but I imagine it could easily be dynamic with a little Flash remoting. The cool thing is that existing grid data item is pre-selected if it exists in the select's dataprovider. In the example, you'll also see that when the selected item changes, the data is populated in the appropriate grid cell.

Here's the code - first the cfm page:

<cfform format="flash" name="test" onload="setCellRenderer();">
<cfformitem type="script">

function setCellRenderer(){
testGrid.getColumnAt(2).cellRenderer = ComboBoxCell;
}
</cfformitem>
<cfformitem type="spacer"/>
<cfformgroup type="horizontal">
<cfgrid name="testGrid" width="260" selectmode="edit">
<cfgridcolumn name="dataCol" header="data col" width="100">
                <cfgridrow data="data,low">
                <cfgridrow data="data,medium">
                <cfgridrow data="data">
<cfgridcolumn name="sel" header="select" width="200">
</cfgrid>
         <cfinput type="button" name="testbtn" value="Show Value in Grid" onclick="alert(testGrid.selectedItem.sel);">
    </cfformgroup>
</cfform>

Now the ComboBoxCell.as - residing in the same directory as the cfm page:

import mx.core.UIComponent
import mx.controls.ComboBox

class ComboBoxCell extends UIComponent
{
    var combo : MovieClip;
    var owner : MovieClip;    // The row that contains the cell.
    var listOwner : MovieClip; // the reference we receive to the list
    var getCellIndex : Function; // the function we receive from the list
    var    getDataLabel : Function; // the function we receive from the list
    private static var COMBOBOX_DATA_PROVIDER : Array = [{label:"", data:""},
                                        {label: "unrated", data: "unrated"},
                                        {label: "low", data: "low"},
                                        {label: "medium", data: "medium"},
                                        {label: "high", data: "high"}];
    function ComboBoxCellRenderer()
    {
    }

    function createChildren(Void) : Void
    {        
        //Creates a ComboBox object and listen to changes
        combo = createObject("ComboBox", "Combo", 0, {styleName:this, owner:this});
        combo.addEventListener("change", this);
        combo.dataProvider = COMBOBOX_DATA_PROVIDER;
        size();
    }

    // note that setSize is implemented by UIComponent
    //and calls size(), after setting
    // __width and __height
    function size(Void) : Void
    {
        
    var h = __height;
var w = __width;
combo.setSize(w - 2, Math.max(h, listOwner.rowHeight - 2));    
    }

public function setValue(str:String, item:Object, sel:Boolean) : Void
    {
        /* Sets the ComboBox to the correspoinding
        cell data from the list owner's data provider
        if the cell data matches
        with any items available for the ComboBox. */

        
        var drawCombo:Boolean = true;
        if (item[getDataLabel()]!=undefined)
        {
            /* For each item's data in the ComboBox, verify if it matches
            the assigned data for the cell this ComboBox is in.
            Set the selectedIndex of the ComboBox to what matches. */

            for(var i:Number = 0; i < combo.length; i++)
            {
                if( combo.getItemAt(i).data == item[getDataLabel()] )
                {
                    combo.selectedIndex = i;
                    break;
                }
                if ( i == combo.length - 1 )
                {
                    // There was no matching data, the ComboBox should not be shown.
                    //drawCombo = false;
                    // The original function hid the combobox if no data, i leave it in
                }
            }
        }
        else
        {
            // There was no data, set the combobox to blank
            combo.selectedIndex = 0;
        }
        
        combo._visible = drawCombo;
    }

    function getPreferredHeight(Void) : Number
    {
        return owner.__height;
    }

    function getPreferredWidth(Void) : Number
    {
        return owner.__width;
    }
    // This re-builds the dataProvider, the selected item
    // as the first in the array
    function reorder(datos:Array, choice:String):Array {
        var index:Number = 0
        var newArray = new Array()
        for(var i=0; i<datos.length; i++){        
            if(datos[i].label!=choice){
                index++
                newArray[index] = datos[i]
            } else newArray[0] = datos[i]
        }    
        return newArray
    }


    
    public function change()
    {
        // Handler for the ComboBox change event.
        
        // Set the listOwner's data to the currently selected item's data of the combo box.
        listOwner.dataProvider.editField(getCellIndex().itemIndex, getDataLabel(), combo.selectedItem.data);    
        listOwner.selectedIndex = getCellIndex().itemIndex;
    }

}

Live Example.

Related Blog Entries

Comments (23)

Steve's Gravatar Hello, I am unable to get this code to run? Am I doing something incorrect? Basically I have found that as soon as that script is call the flash form does not load. Any help would be much appreciated.

todd's Gravatar Steve:

Are you saving ComboBoxCell.as in the same directory as the cfm page? Did you make any changes to the ComboBoxCell.as file? If there are errors in the Actionscript code the form won't load (and it won't give you an error sometimes either) :(
Post your AS code here if you've made changes and I'll see if I can spot any errors.

ray's Gravatar Is there a way to populate the combo box with a query instead of hard-coding?

todd's Gravatar ray:

Check out my post tomorrow morning - I'll show how to populate with a query.

todd

boybles's Gravatar Did I miss something? Did you ever post an example of how to populate with a Query???

boybles's Gravatar Never mind...I just found it on the 6/30 post. Great work, Todd!!

Jason's Gravatar I copied and pasted the information found above into two new files and ran the .cfm file. The Flash form won't load unless I comment out onload="setCellRenderer();" and the entire <cfformitem type="script>...</cfformitem>.

I'm using MX7 on a Windows XP machine. Nothing else is in either file except for the code above.

What am I missing? Thanks!

todd sharp's Gravatar What version of 7 are you running? cfformitem type = script was not introduced until 7.0.1.

Jason's Gravatar I'm running 7,0,2,142559. If you're available to talk through IM, you can reach me on AIM or Yahoo at JasonCTIstl.

Bingo's Gravatar Great stuff, my customers like the look and feel, and I like how easy it was to get all the sorting and resizing into a "code table".

Has anyone run into a problem, when using a dynamic source for the combo box, of the Grid rendering and being presented without the combo box? It seems that the combo box only appears about 1/3 of the time. Is there something I need to use to "slow down" the rendering of the grid until after the combo box has been created?

todd sharp's Gravatar Bingo: I've seen that, but I haven't touched a Flash Form in so long I honestly can't remember if there is a fix. Is Flex not an option for you? You'd be much happier in the long run I think if you could make the switch.

Bingo's Gravatar Unfortunately, Flex isn't currently an option. The powers-that-be are still debating between OpenLaszlo and Flex as a development standard. My CFGRIDs are being used in production, and the combo-box rendering was one of their "get to it when you can" items I finally have a chance to look into.

Once we do settle on a UI, I will be re-writing those code tables, but was basically checking to make sure I wasn't alone, or if someone had a silver bullet to solve my problem.

Thanks!!

kashi's Gravatar How can add a checkbox component into a list component in flash..can u pls help me with the source code..

Kashi(NDS)'s Gravatar Its done by using cell rendering method-by overriding the component class with 4 methods.

John's Gravatar How would you accomplish this with cfgrid format="html"?

I have a cfgrid bound to a cfc. It'll have one (and only one) editable column, ActiveStateID, which will be a select box on each row. My attempt to do this includes:

<cfgrid selectmode="edit" format="html" [snip] >
<cfgridcolumn name="ActiveStateID" header="State" select="yes" display="yes" values="1,2,3" valuesdisplay="Active,Enabled,Paused">
[snip]
</cfgrid>

The problem is that this gives me an ActiveStateID column containing the integer values of the foreign key (1, 2, or 3) instead of select boxes with Active, Enabled, and Paused and the correct option selected.

Ideas...?

Dan Konig's Gravatar I'd like to know how to do this with a HTML cfgrid as well. I have a single column that will be updated based on the status of the client and a combox/dropdown list would be great.

todd sharp's Gravatar Check this for HTML grids:

http://www.danvega.org/blog/index.cfm/2008/3/12/Cu...

Hope that helps.

Dan's Gravatar THanks Todd but I have that part nailed down. The issue I run into is twofold.

1. The dropdown only works if the the cell is empty.
2. once a selection is made and the DB is updated the dropdown stops working and the cell becomes uneditable.

At least this has been my experience. Anyone find a way to work around this?

Jonathan's Gravatar I got the code to work but then I try to change the OMBOBOX_DATA_PROVIDER Array and the page never updates. It's like the information is cached on the server or my client or something. Anyone run into this?

Kenji's Gravatar I was wondering if there is a way to include this code in the same page as the grid, without needing the external reference. I have gotten this code to work with one data grid, but now I need it for another one in a different file, with different values for the select, and I can't very well have two files named comboboxcell.as in the same directory.

I can't seem to rename the file to anything else, not even renaming the classes seem to work.

I can't put it in a sub directory because there is no way to reference it (that I can find).

I can't seem to put both the new page, and the new comboboxcell.as in a new sub directory, because it pulls the comboboxcell.as from the directory above.

I can't seem to just copy and paste the code into a script form item, because then nothing loads.

I am totally out of ideas. How can I have another combobox?! Thanks for any help, I really appreciate it. By the way, your code does rock, the other page where I am already using it works like a dream, I love it (hence the reason I want it so badly on this other page!).

todd sharp's Gravatar To be honest I haven't touched a Flash Form in years so I don't think I can help with that. Good luck though.

Kenji's Gravatar Dang, alright well thanks for the reply anyway. I think I'm just going to work around it.

todd sharp's Gravatar Have you checked out Flex at all? I'd strongly recommend it!