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

<cfform format="flash" name="testForm" onload="getSelectData();">
<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

<cfcomponent name="cellRendererSelect" access="public" description="Gets Data for the cell Renderer Select">

<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.core.UIComponent
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;
    }

}

Related Blog Entries

Comments (9)

Michael White's Gravatar having a little trouble copying the code into a new page... the single-line comments and line breaks aren't working which forces me to guess where the comment ends (particularly in the AS file)

todd's Gravatar Yeah, I should probably start putting up zip files so the code could be downloaded easily. I'll throw one up for this later today.

todd's Gravatar Just updated the post to add a zip so you can download the code.

Michael White's Gravatar Code downloaded: you da man!

Ray Manalo's Gravatar Hi,

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!

Oliver's Gravatar Thanx allot for that example, I have found a buggy problem though. When I replaced the static query with a db query, the select boxes only seem to show like 50% of the time, when I refresh the page. Not sure where to even start debugging.

Oliver's Gravatar It seems the page can run faster than the query. when I tossed in a cachedwithin in the cfquery the query works 100% after it catches. Not sure why/how the sql script gets skipped/lags out.

Steve's Gravatar I have the same problems with the combo box not always showing up. I even tried the cached within, but it still doesn't always work.

Any ideas?

NleonWill's Gravatar How can I create a column in a cfgrid with a combo box? I want to do this with query results from SQL Server and not a remote service?