New to Telerik UI for ASP.NET AJAXStart a free 30-day trial

Cascading ComboBoxes in Grid with BatchEdit

Environment

Product
RadGrid
RadComboBox

Description

In general cascading ComboBoxes handled across PostBacks is easy. However, BatchEdit is a Client-Side (JavaScript-based) functionality of the Grid, therefore, interaction with the Grid must be done on the Client-Side. Having that in mind, PostBacks must not happen, otherwise, the editing will be interrupted and all changes lost.

The following article describes the main aspects of Batch Editing: RadGrid Batch Editing Templates and Specifics.

If no, PostBacks can be done, what would be the solution? Using the Client-Side APIs of both the Grid and the ComboBoxes to interact with them.

Solution

Default.aspx

Create the Grid structure with two GridTemplateColumns, each of which containing one RadComboBox.

XML
<h3>Colours available /model</h3>
<ul>
    <li>Sedan: 1, 5, 7, 11, 13</li>
    <li>Coupe: 2, 4, 8, 10, 14</li>
    <li>Hatchback: 3, 6, 9, 12, 15</li>
</ul>

<telerik:RadGrid ID="RadGrid1" runat="server" Width="600px"
    OnNeedDataSource="RadGrid1_NeedDataSource"
    OnPreRender="RadGrid1_PreRender">
    <ClientSettings>
        <ClientEvents OnBatchEditOpened="OnBatchEditOpened" />
    </ClientSettings>
    <MasterTableView AutoGenerateColumns="False" EditMode="Batch" CommandItemDisplay="Top">
        <BatchEditingSettings EditType="Row" />
        <Columns>

            <telerik:GridTemplateColumn UniqueName="CarModel" HeaderText="Car Model">
                <ItemTemplate>
                    <%# Eval("CarModel") %>
                </ItemTemplate>
                <EditItemTemplate>
                    <telerik:RadComboBox ID="Combo_CarModel"
                        OnClientDropDownClosed="ComboCarModel_DropDownClosed"
                        runat="server"
                        DataTextField="CarModel"
                        DataValueField="CarModel"
                        DropDownAutoWidth="Enabled"
                        HighlightTemplatedItems="true">
                    </telerik:RadComboBox>
                </EditItemTemplate>
            </telerik:GridTemplateColumn>

            <telerik:GridTemplateColumn UniqueName="ModelColor" HeaderText="Model Color">
                <ItemTemplate>
                    <%# Eval("ModelColor") %>
                </ItemTemplate>
                <EditItemTemplate>
                    <telerik:RadComboBox ID="Combo_ModelColor"
                        OnClientItemsRequesting="ModelColorRequesting"
                        runat="server"
                        DataTextField="ModelColor"
                        DataValueField="ModelColor"
                        NoWrap="true"
                        DropDownAutoWidth="Enabled"
                        EnableLoadOnDemand="true"
                        OnItemsRequested="Combo_ModelColor_ItemsRequested"
                        AppendDataBoundItems="false"
                        HighlightTemplatedItems="true">
                    </telerik:RadComboBox>
                </EditItemTemplate>
            </telerik:GridTemplateColumn>

        </Columns>
    </MasterTableView>
</telerik:RadGrid>

JavaScript logic that will interact with the Client-Side APIs of the BatchEditing and the Client-Side APIs of the ComboBox

JavaScript
<script type="text/javascript">
    // When the Cell has opened for editing
    function OnBatchEditOpened(sender, args) {
        if (args.get_columnUniqueName() != "ModelColor") return;

        // Container is the cell
        ResetComboModelColor(args.get_cell());
    }
    // If the DropDown element Closes even if the Grid cell does not open again
    function ComboCarModel_DropDownClosed(sender, args) {

        // Container is the entire row that is being edited currently
        var currentRow = $(sender.get_element()).closest('tr')[0];

        ResetComboModelColor(currentRow);
    }

            
    function ResetComboModelColor(container) {
        // Get reference to the second Combo in the container
        var ComboModelColor = $telerik.findControl(container, "Combo_ModelColor");
        // Clear the Existing Text
        ComboModelColor.set_text("");
        // Make the Combo Request new Items
        ComboModelColor.requestItems();
    }

    // Event that fires upon requesting new items
    function ModelColorRequesting(sender, args) {
        var context = args.get_context();
        var currentRow = $(sender.get_element()).closest('tr')[0];
        var ComboCarModel = $telerik.findControl(currentRow, "Combo_CarModel");
        // Send the Context to the server. Contains the Parent Combo's relational value
        context["CarModel"] = ComboCarModel.get_value();
    }
</script>

Default.aspx.cs

Bind data to RadGrid and the main ComboBox. The second ComboBox will use the ItemsRequested event to bind to data in relation to the Main ComboBox using the current Context.

C#
protected void RadGrid1_NeedDataSource(object sender, GridNeedDataSourceEventArgs e)
{
    (sender as RadGrid).DataSource = Cars();
}

private DataTable Cars()
{
    DataTable dt = new DataTable();

    dt.Columns.Add("ID", typeof(int));
    dt.Columns.Add("CarModel", typeof(string));
    dt.Columns.Add("ModelColor", typeof(string));

    for (int i = 0; i < 15; i++)
    {
        int index = i + 1;

        DataRow dr = dt.NewRow();

        dr["ID"] = index;

        if (index % 3 == 0) { dr["CarModel"] = "Hatchback"; }
        else if (index % 2 == 0) { dr["CarModel"] = "Coupe"; }
        else { dr["CarModel"] = "Sedan"; }

        dr["ModelColor"] = "Color " + index;

        dt.Rows.Add(dr);
    }

    return dt;
}

protected void Combo_ModelColor_ItemsRequested(object sender, RadComboBoxItemsRequestedEventArgs e)
{
    var combo = (RadComboBox)sender;

    object carModel;

    e.Context.TryGetValue("CarModel", out carModel);
        
    combo.DataSource = Cars().Select(string.Format("CarModel = '{0}'", carModel.ToString())).CopyToDataTable();
    combo.DataBind();
}

protected void RadGrid1_PreRender(object sender, EventArgs e)
{
    var combo = ((sender as RadGrid).MasterTableView.GetBatchEditorContainer("CarModel").FindControl("Combo_CarModel") as RadComboBox);
    combo.DataSource = Cars().DefaultView.ToTable(true, "CarModel");
    combo.DataBind();
}

See Also