New to Telerik UI for ASP.NET AJAX? Download 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.

<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

<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.

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

In this article