New to Telerik UI for ASP.NET MVC? Download free 30-day trial

Row and Column Spanning

The Row and Column spanning functionality provides the option to customize the appearance of the Grid and span cells between multiple row or columns. This feature is equal to 'cell merging' in Excel or 'row spanning' and 'column spanning' in HTML tables.

Row Spanning

The Row spanning functionality of the Grid enables you to span a cell between multiple rows. You can use one of the Columns.HtmlAttributes overload and pass the name of the JavaScript handler function that will set the attributes for the column. The function will receive the dataItem as a parameter and you use tha data to calculate the span of each cell. In the attributes function you can apply the rowSpan and hidden attributes to the cells.

The rowspan attribute defines the number of rows a table cell needs to span. The hidden attribute must be added to cells that should not be displayed when a condition or hiding a cell is met.

The example below demonstrates how to implement row spanning when the ShipCity field for consequtive cells has the same value:

    @(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.OrderViewModel>()    
        .Name("grid")
        .Columns(columns => {
            columns.Bound(p => p.OrderID).Filterable(false).Width(100);
            columns.Bound(p => p.Freight).Width(100);
            columns.Bound(p => p.OrderDate).Format("{0:MM/dd/yyyy}").Width(140);
            columns.Bound(p => p.ShipName);
            columns.Bound(p => p.ShipCity).HtmlAttributes("setRowSpan").Width(150);
        })
        .Pageable()
        .Sortable()
        .Scrollable()
        .Filterable()
        .HtmlAttributes(new { style = "height:430px;" })
        .DataSource(dataSource => dataSource
            .Ajax()
            .PageSize(20)
            .Read(read => read.Action("Orders_Read", "Grid"))
            .Sort(s=>s.Add(f=>f.ShipName).Ascending())
        )
    )
    function setRowSpan(dataItem) {
        const dataView = dataItem.parent();
        let currentIndex = dataView.indexOf(dataItem);
        const prevDataItem = currentIndex === 0 ? null : dataView.at(currentIndex - 1);
        let nextDataItem = dataView.at(++currentIndex);
        let rowSpan = 1;

        if (prevDataItem && dataItem["ShipCity"] === prevDataItem["ShipCity"]) {
            return {
                hidden: 'hidden'
            }
        }

        while (nextDataItem) {
            if (prevDataItem && dataItem["ShipCity"] === prevDataItem["ShipCity"]) {
                rowSpan++;
            } else {
                break;
            }

            nextDataItem = dataView.at(++currentIndex);
        }

        return { rowSpan };
    }

Column Spanning

The Column spanning functionality enables you to span multiple columns in the Grid. To implement Column spanning use one of the Columns.HtmlAttributes overload and pass the name of the JavaScript handler function that will set the attributes for the column. You can then set the colSpan and hidden attributes to the cells.

The colspan attribute defines the number of columns a table cell needs to span. The hidden attribute must be added to cells that should not be displayed when a condition is met. Additionally, you can also add different styling attributes or CSS classes to the <td> element of the cell. This allows you to style the spanned cells.

The following example demonstrates how you can implement row spanning for products that are discontinued:

    @(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.ProductViewModelGridPopUp>()
        .Name("grid")
        .Columns(columns =>
        {
            columns.Bound(p => p.ProductName);
            columns.Bound(p => p.UnitPrice).HtmlAttributes("hiddenHandler").Width(100);
            columns.Bound(p => p.UnitsInStock).HtmlAttributes("hiddenHandler").Width(100);
            columns.Bound(p => p.Discontinued).HtmlAttributes("discontinuedHandler").ClientTemplate("#=Discontinued ? 'Product is Not Available' : 'Available'#").Width(100);
            columns.Command(command => { command.Edit(); command.Destroy(); }).Width(200);
        })
        .ToolBar(toolbar => toolbar.Create())
        .Editable(editable => editable.Mode(GridEditMode.PopUp))
        .Pageable()
        .Sortable()
        .Scrollable()
        .HtmlAttributes(new { style = "height:430px;" })
        .DataSource(dataSource => dataSource
            .Ajax()
            .PageSize(20)
            .Model(model => model.Id(p => p.ProductID))
            .Create(update => update.Action("EditingPopup_Create", "Grid"))
            .Read(read => read.Action("EditingPopup_Read", "Grid"))
            .Update(update => update.Action("EditingPopup_Update", "Grid"))
            .Destroy(update => update.Action("EditingPopup_Destroy", "Grid"))
        )
    )
    function discontinuedAttributesHandler(dataItem) {
        if (dataItem.Discontinued) {
            return {
                colSpan: 3,
                "class": "!k-text-center"
            };
        } else {
            return {
                "class": "!k-text-center"
            };
        }
    };

    function hiddenHandler(dataItem) {
        if (dataItem.Discontinued) {
            return { hidden: "hidden" };
        }
    };

Column Spanning with Server Binding

When the Telerik UI for ASP.NET MVC Grid is configured for Server Binding only column spanning is supported. If you need to use row spannig use Ajax binding.

When implementing column spannig for Server bound Grid you can use the AddServerAttribute configuration method. Define the attribute that should be added and the condition based on which the attribute's value will be assigned:

The example below demonstrates how to define the conditions based on which the value of the colspan attribute should be set and the k-hidden class added to Grid cells. Adding additional styling is also supported:

    @model IEnumerable<Kendo.Mvc.Examples.Models.Product>

    @(Html.Kendo().Grid(Model)
        .Name("Grid")
        .Columns(columns => {
            columns.Bound(p => p.ProductID).Groupable(false);
            columns.Bound(p => p.ProductName);
            columns.Bound(p => p.UnitPrice)
                        .AddServerAttribute("class", (p) => p.Discontinued == true ? "k-hidden" : "");
            columns.Bound(p => p.UnitsInStock)
                        .AddServerAttribute("colSpan", (p) => p.Discontinued == true ? "3" : "1")
                        .AddServerAttribute("class", (p) => p.Discontinued == true ? "!k-text-center" : "")
                        .AddServerAttribute("style", (p) => p.Discontinued == true ? "color: red;" : "")
                        .Template(@<text>
                                @if(item.Discontinued)
                                    {
                                        <span>Product Not Available</span>
                                    }
                                    else
                                    {
                                        @item.UnitsInStock
                                    }
                            </text>);
            columns.Bound(p => p.Discontinued).AddServerAttribute("class", (p) => p.Discontinued == true ? "k-hidden" : "");
                    })
        .Pageable()
        .Sortable()
        .Filterable()
        .Groupable()
    )

See Also

In this article