CFGRID ComboBox Cell Renderer - Dynamic Query
Posted By : todd sharp Posted At : June 30, 2006 5:42 AM Posted In: Flash Forms, ActionScript, ColdFusion
9
As a follow up to my original post, here's an example of creating a combobox cell renderer for a cfgrid which is populated with a query rather than a hardcoded dataprovider. The trick is to use flash remoting to get the query, set a global variable containing the results, then call the renderer and use the global variable to set the combobox dataprovider.
The example still looks the same, but obviously this method is much more dynamic. There is one change in the AS file for the renderer. Since we're using a query from remoting, we can't access combo.selectedItem.data. Instead, we reference the column name from the query - in this case it's combo.selectedItem.priority.
Update: Download the Code.
selectRendererWithQuery.cfm
<cfformitem type="script">
function getSelectData(){
//create connection
<cfoutput>
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection("http://#cgi.HTTP_HOST#/flashservices/gateway/");
</cfoutput>
//declare service
var myService:mx.remoting.NetServiceProxy;
var responseHandler = {};
var COMBOBOX_DATA_PROVIDER = COMBOBOX_DATA_PROVIDER;
responseHandler.onResult = function( results: Object ):Void {
//when results are back, populate the COMBOBOX_DATA_PROVIDER
//then set the cellRenderer
_global.COMBOBOX_DATA_PROVIDER = results;
_root.testGrid.getColumnAt(2).cellRenderer = ComboBoxCellNew;
}
responseHandler.onStatus = function( stat: Object ):Void {
//if there is any error, show an alert
alert("Error while calling cfc:" + stat.description);
}
//get service
myService = connection.getService("blog.tips.cellRendererSelect", responseHandler );
//make call
myService.getPriorities();
}
</cfformitem>
<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="check" header="check box" width="200">
</cfgrid>
<cfinput type="button" name="testbtn" value="Show Value in Grid" onclick="alert(testGrid.selectedItem.check);">
</cfformgroup>
</cfform>
cellRendererSelect.cfc
<cffunction name="getPriorities" output="false" description="Returns a query" access="remote" returntype="query">
<cfset qPriorities = queryNew("priority")>
<cfset temp = queryAddRow(qPriorities, 4)>
<cfset temp = querySetCell(qPriorities, "priority", "", 1)>
<cfset temp = querySetCell(qPriorities, "priority", "low", 2)>
<cfset temp = querySetCell(qPriorities, "priority", "medium", 3)>
<cfset temp = querySetCell(qPriorities, "priority", "high", 4)>
<cfreturn qPriorities />
</cffunction>
</cfcomponent>
ComboBoxCellNew.as
import mx.controls.ComboBox
class ComboBoxCellNew 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
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.labelField = "priority";
combo.dataProvider = _global.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).priority == item[getDataLabel()] )
{
combo.selectedIndex = i;
break;
}
if ( i == combo.length - 1 )
{
// There was no matching data, the ComboBox should not be shown.
//drawCombo = false;
}
}
}
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-build 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.priority);
listOwner.selectedIndex = getCellIndex().itemIndex;
}
}



I read your previous post and it has helped tremendously for hard-coding a dataprovider. I was wondering however, is this technique also possible to do without remoting? Can a combo box be placed in a cfgrid and populated via a cfquery without remoting??
Thanks!
Any ideas?