CFGRID Cell Renderer - ComboBox (Select)
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:
<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.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;
}
}



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.
Check out my post tomorrow morning - I'll show how to populate with a query.
todd
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!
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?
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!!
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...?