RadGrid BatchEdit - How to TAB to first cell of next row

3 Answers 55 Views
Grid
Thomas
Top achievements
Rank 1
Iron
Iron
Thomas asked on 09 Feb 2022, 04:51 PM

I have a web page with a RadGrid in Batch Edit mode.  The number and width of the columns makes the grid wider than the browser window, so it scrolls horizontally.  I followed this example to allow me to TAB from cell to cell in the table and to scroll the grid horizontally as the cursor moves from column to column.  When I get to the last cell in a row, pressing TAB moves me to the next row, but it moves me to the first visible column on the row rather than scrolling the page all the way back to the left edge and moving me to the first column.

Is there a way to reset the horizontal scrolling when I TAB from the last cell so it goes back to the left most column?

3 Answers, 1 is accepted

Sort by
0
Accepted
Thomas
Top achievements
Rank 1
Iron
Iron
answered on 16 Feb 2022, 02:12 PM

Attila,

Here is the re-work of the testPage.zip example from the post I referenced in the problem description.  It is inelegant but it gets scrolling working using TAB and SHIFT-TAB when using frozen columns and static headers.

Note: It relies on every column having a UNIQUE NAME.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
	<title></title>
	<telerik:RadStyleSheetManager ID="RadStyleSheetManager1" runat="server" />
</head>
<body>
	<form id="form1" runat="server">
		<telerik:RadScriptManager ID="RadScriptManager1" runat="server">
			<Scripts>
				<asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.Core.js" />
				<asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.jQuery.js" />
				<asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.jQueryInclude.js" />
			</Scripts>
		</telerik:RadScriptManager>
		<script type="text/javascript">

			function OnGridCreated(sender, args)
			{
				// Resize columns to fit data
				var grid = $find("RadGrid1");
				var columns = grid.get_masterTableView().get_columns();
				for (var i = 0; i < columns.length; i++) {
					columns[i].resizeToFit();
				}

				// Assign function to recalculate scrolling
				var frozenScroll = $get(grid.get_id() + "_Frozen");
				var allColumns = grid.get_masterTableView().get_columns();
				var scrollLeftOffset = 0;
				var allColumnsWidth = new Array;
				var lastWidth = 0;

				for(var i = 0; i < allColumns.length; i++)
				{
					allColumnsWidth[i] = allColumns[i].get_element().offsetWidth;
				}

				$get(grid.get_id() + "_GridData").onscroll = function (e)
				{
					for(var i = 0; i < allColumns.length; i++)
					{
						if(!allColumns[i].get_visible())
						{
							scrollLeftOffset += allColumnsWidth[i];
							lastWidth = allColumnsWidth[i];
						}
					}
					var thisScrollLeft = this.scrollLeft;
					this.scrollLeft = 0;
					if (thisScrollLeft > 0)
					{
						// To insure the current cell is not on the right edge, add the last column's width
						frozenScroll.scrollLeft = thisScrollLeft + scrollLeftOffset + lastWidth;
					}
					scrollLeftOffset = 0;
				}
			}

			function OnKeyDown(event)
			{
				// Look for TAB
				if (event.which == 9)
				{
					var grid = $find("RadGrid1");

					var columnName = event.target.name.split("$TB_")[1];
					var masterTableView = grid.get_masterTableView(); 
					var column = masterTableView.getColumnByUniqueName(columnName); 
					var element = column.get_element(); 
					var index = element.cellIndex; 
					var numColumns = grid.get_masterTableView().get_columns().length - 1;

					var frozenScroll = $get(grid.get_id() + "_Frozen");

					if (event.shiftKey == false)
					{
						if (index == numColumns)
						{
							// Reset scroll position to left edge
							frozenScroll.scrollLeft = 0;
						}
					}
					else
					{
						// Reduce the scroll position by the current cell's width
						frozenScroll.scrollLeft = frozenScroll.scrollLeft - column.get_element().offsetWidth;
					}
				}
				
			}
		</script>
		<telerik:RadAjaxManager ID="RadAjaxManager1" runat="server">
		</telerik:RadAjaxManager>
		<div>
			<telerik:RadGrid ID="RadGrid1" runat="server"
				OnNeedDataSource="RadGrid1_NeedDataSource"
				AutoGenerateColumns="False" onkeydown="OnKeyDown(event);">
				<ClientSettings AllowKeyboardNavigation="True">
					<Scrolling FrozenColumnsCount="2" AllowScroll="True" ScrollHeight="600px" UseStaticHeaders="True"></Scrolling>
					<Selecting CellSelectionMode="None" AllowRowSelect="True"></Selecting>
					<ClientEvents OnGridCreated="OnGridCreated" />
					<Resizing AllowColumnResize="True" AllowResizeToFit="True" ClipCellContentOnResize="False" />
				</ClientSettings>
				<AlternatingItemStyle Wrap="True" BackColor="Gainsboro"></AlternatingItemStyle>
				<MasterTableView CommandItemDisplay="TopAndBottom" DataKeyNames="PeopleID" EditMode="Batch" TableLayout="Fixed">
					<BatchEditingSettings EditType="Row" />
					<Columns>
					</Columns>
					<CommandItemSettings ShowAddNewRecordButton="False" />
				</MasterTableView>

				<HeaderStyle VerticalAlign="Bottom" Font-Bold="True" BackColor="DarkSeaGreen" Wrap="False"></HeaderStyle>

				<ActiveItemStyle Wrap="True"></ActiveItemStyle>

			</telerik:RadGrid>
		</div>
	</form>
</body>
</html>

 


using System;
using Telerik.Web.UI;
using System.Data;

public partial class Default : System.Web.UI.Page
{
    protected void RadGrid1_NeedDataSource(object sender, GridNeedDataSourceEventArgs e)
    {
        DataTable dt = new DataTable();
        DataRow dr;
        int rowsNum = 130;
        string[][] colsInfo = {
        new string[] { "PeopleID", "number" },
        new string[] { "Custom1", "string" },
        new string[] { "Custom2", "string" },
        new string[] { "Custom3", "string" },
        new string[] { "Custom4", "string" },
        new string[] { "Custom5", "string" },
        new string[] { "Custom6", "string" },
        new string[] { "Custom7", "string" },
        new string[] { "Custom8", "string" },
        new string[] { "Custom9", "string" },
        new string[] { "Custom10", "string" },
        new string[] { "Custom11", "string" },
        new string[] { "Custom12", "string" },
        new string[] { "Custom13", "string" },
        new string[] { "Custom14", "string" },
        new string[] { "Custom15", "string" },
        new string[] { "Custom16", "string" },
        new string[] { "Custom17", "string" },
        new string[] { "Custom18", "string" },
        new string[] { "Custom19", "string" },
        new string[] { "Custom20", "string" },
	};

        for (int i = 0; i < colsInfo.Length; i++)
        {
            GridBoundColumn newColumn = new GridBoundColumn();
            newColumn.DataField = colsInfo[i][0];
            newColumn.UniqueName = colsInfo[i][0];
            newColumn.HeaderText = "*" + colsInfo[i][0] + "*";
            RadGrid1.MasterTableView.Columns.Add(newColumn);

            switch (colsInfo[i][1])
            {
                case "string":
                    dt.Columns.Add(new DataColumn(colsInfo[i][0], typeof(String)));
                    break;
                case "number":
                    dt.Columns.Add(new DataColumn(colsInfo[i][0], typeof(Int32)));
                    break;
                case "date":
                    dt.Columns.Add(new DataColumn(colsInfo[i][0], typeof(DateTime)));
                    break;
                case "bool":
                    dt.Columns.Add(new DataColumn(colsInfo[i][0], typeof(Boolean)));
                    break;
                default:
                    break;
            }
        }

        for (int j = 1; j <= rowsNum; j++)
        {
            dr = dt.NewRow();

            for (int k = 0; k < colsInfo.Length; k++)
            {
                switch (colsInfo[k][1])
                {
                    case "string":
                        dr[colsInfo[k][0]] = String.Format("{0} Row{1}", colsInfo[k][0], j);
                        break;
                    case "number":
                        dr[colsInfo[k][0]] = j;
                        break;
                    case "date":
                        dr[colsInfo[k][0]] = DateTime.Now;
                        break;
                    case "bool":
                        dr[colsInfo[k][0]] = j % 2 == 1 ? true : false;
                        break;
                    default:
                        break;
                }
            }
            dt.Rows.Add(dr);
        }

        (sender as RadGrid).DataSource = dt;
    }
}
If you see any opportunities for improving this, I welcome your input.
0
Attila Antal
Telerik team
answered on 14 Feb 2022, 11:26 AM | edited on 14 Feb 2022, 11:27 AM

Hi Thomas,

The solution in the articles you shared was provided for a specific scenario. You might be using an entirely different scenario, hence, that code will not be compatible.

 

RadGrid by default can handle the Scrolling when Tabbing and there is no need to implement it additionally. You can check out the attached GIF image to see it in action.

 

Here is the Grid setup

<telerik:RadGrid ID="RadGrid1" runat="server" AllowPaging="True" Width="800px" OnNeedDataSource="RadGrid1_NeedDataSource">
    <ClientSettings AllowKeyboardNavigation="true">
        <Scrolling AllowScroll="true" UseStaticHeaders="true" />
    </ClientSettings>
    <MasterTableView AutoGenerateColumns="False" DataKeyNames="OrderID" EditMode="Batch" TableLayout="Fixed">
        <HeaderStyle Width="300px" />
        <Columns>
            <telerik:GridBoundColumn DataField="OrderID" DataType="System.Int32"
                FilterControlAltText="Filter OrderID column" HeaderText="OrderID"
                ReadOnly="True" SortExpression="OrderID" UniqueName="OrderID">
                <HeaderStyle Width="100px" />
            </telerik:GridBoundColumn>
            <telerik:GridDateTimeColumn DataField="OrderDate" DataType="System.DateTime"
                FilterControlAltText="Filter OrderDate column" HeaderText="OrderDate"
                SortExpression="OrderDate" UniqueName="OrderDate">
            </telerik:GridDateTimeColumn>
            <telerik:GridNumericColumn DataField="Freight" DataType="System.Decimal"
                FilterControlAltText="Filter Freight column" HeaderText="Freight"
                SortExpression="Freight" UniqueName="Freight">
            </telerik:GridNumericColumn>
            <telerik:GridBoundColumn DataField="ShipName"
                FilterControlAltText="Filter ShipName column" HeaderText="ShipName"
                SortExpression="ShipName" UniqueName="ShipName">
            </telerik:GridBoundColumn>
            <telerik:GridBoundColumn DataField="ShipCountry"
                FilterControlAltText="Filter ShipCountry column" HeaderText="ShipCountry"
                SortExpression="ShipCountry" UniqueName="ShipCountry">
            </telerik:GridBoundColumn>
        </Columns>
    </MasterTableView>
</telerik:RadGrid>

<script runat="server">
    protected void RadGrid1_NeedDataSource(object sender, GridNeedDataSourceEventArgs e)
    {
        (sender as RadGrid).DataSource = Enumerable.Range(1, 10).Select(x => new
        {
            OrderID = x,
            OrderDate = DateTime.Now.Date.AddDays(x),
            Freight = x * .1,
            ShipName = "Name " + x,
            ShipCountry = "Country " + x
        });
    }
</script>

 

If this doesn't work for you, then you likely have a scenario specific to your requirements and will require a different approach.

Can you share the reason you had to implement the JavaScript from the other forum post? We might be able to give you some advice.

 

Regards,
Attila Antal
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Thomas
Top achievements
Rank 1
Iron
Iron
commented on 14 Feb 2022, 02:15 PM | edited

Hello Attila,

I want to have frozen columns AND static headers, so no matter which way I scroll, they will stay on the screen.  This link seems to say that what I am trying to do is unsupported.

When frozen columns are used, tabbing between the textboxes in an inline edit form is not supported out-of-the-box, because the frozen columns will be scrolled together with the non-frozen. In selected scenarios, this functionality can be achieved if you subscribe to the textboxes' focus events and scroll a specific <div> with Javascript. This <div> has a client ID of <RadGridInstance.ClientID>_Frozen. When doing this, you should take into account the current scroll position, and the width of the column that should be hidden/shown.

However, when I implemented the JavaScript from the other post it did not scroll left when I used SHIFT TAB and when the TAB reaches the right end of the row, it doesn't go to the first record of the next line - it goes to the first visible column of the next line.

0
Attila Antal
Telerik team
answered on 22 Feb 2022, 12:05 PM

Hello Thomas,

Good findings! Thanks for sharing it with the community!

As a token of gratitude, I have awarded you 1000 Telerik points.

 

The code you wrote is elegant enough. If you wanted to make it more elegant, you could improve that with a little bit of jQuery. 

Below you will see the improvements I made. I have left comments to show the details for the things that I did differently. Of course, even this can be further improved if really needed.

RadGrid markup

<telerik:RadGrid ID="RadGrid1" runat="server"
    OnNeedDataSource="RadGrid1_NeedDataSource"
    AutoGenerateColumns="False">
    <ClientSettings AllowKeyboardNavigation="True">
        <Scrolling FrozenColumnsCount="2" AllowScroll="True" ScrollHeight="600px" UseStaticHeaders="True"></Scrolling>
        <Selecting CellSelectionMode="None" AllowRowSelect="True"></Selecting>
        <ClientEvents OnGridCreated="OnGridCreated" />
        <Resizing AllowColumnResize="True" AllowResizeToFit="True" ClipCellContentOnResize="False" />
    </ClientSettings>
    <AlternatingItemStyle Wrap="True" BackColor="Gainsboro"></AlternatingItemStyle>
    <MasterTableView CommandItemDisplay="TopAndBottom" DataKeyNames="PeopleID" EditMode="Batch" TableLayout="Fixed">
        <BatchEditingSettings EditType="Row" />
        <Columns>
        </Columns>
        <CommandItemSettings ShowAddNewRecordButton="False" />
    </MasterTableView>
    <HeaderStyle VerticalAlign="Bottom" Font-Bold="True" BackColor="DarkSeaGreen" Wrap="False"></HeaderStyle>
    <ActiveItemStyle Wrap="True"></ActiveItemStyle>
</telerik:RadGrid>

 

JavaScript

function OnGridCreated(sender, args) {
    var grid = sender; // Telerik.Web.UI.RadGrid
    var gridElement = grid.get_element(); // <div class="RadGrid"></div>

    // Attach the keydown event
    // https://api.jquery.com/on/
    $telerik.$(gridElement).on('keydown', OnKeyDown);

    var masterTable = grid.get_masterTableView();
    var columns = masterTable.get_columns();

    // Resize all Columns
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
    columns.forEach(col => col.resizeToFit());

    // Collect the width of all columns
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
    var allColumnsWidth = columns.map(col => col.get_element().offsetWidth);

    // Get the Frozen Scroll
    // https://api.jquery.com/attribute-ends-with-selector/#attributevalue
    var frozenScroll = $telerik.$(gridElement).find('div[id$=_Frozen]').get(0); // <div id="RadGrid1_Frozen"></div>

    var scrollLeftOffset = 0;
    var lastWidth = 0;

    // grid.GridDataDiv = <div id="RadGrid1_GridData" class="rgDataDiv">
    // https://docs.telerik.com/devtools/aspnet-ajax/controls/grid/how-to/Scrolling/changing-grid-scrollheight-at-runtime-to-fill-its-container-height
    $telerik.$(grid.GridDataDiv).on('scroll', function (e) {
        for (var i = 0; i < columns.length; i++) {
            if (!columns[i].get_visible()) {
                scrollLeftOffset += allColumnsWidth[i];
                lastWidth = allColumnsWidth[i];
            }
        }
        var thisScrollLeft = this.scrollLeft;
        this.scrollLeft = 0;
        if (thisScrollLeft > 0) {
            // To insure the current cell is not on the right edge, add the last column's width
            frozenScroll.scrollLeft = thisScrollLeft + scrollLeftOffset + lastWidth;
        }
        scrollLeftOffset = 0;
    })
}

function OnKeyDown(event) {
    // Look for TAB
    if (event.which == 9) {
        // https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
        var gridElement = event.currentTarget; // <div class="RadGrid"></div>

        // https://docs.telerik.com/devtools/aspnet-ajax/general-information/get-client-side-reference#using-plain-javascript-methods
        var grid = gridElement.control; // Telerik.Web.UI.RadGrid

        var masterTableView = grid.get_masterTableView();

        // https://developer.mozilla.org/en-US/docs/Web/API/Event/target
        var target = event.target;

        // https://api.jquery.com/closest/
        var currentCell = $telerik.$(target).closest('td.rgBatchCurrent').get(0); // <td class="rgBatchCurrent"></td>

        if (!currentCell) return;

        // https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement
        var cellIndex = currentCell.cellIndex;

        var numColumns = masterTableView.get_columns().length - 1;

        var frozenScroll = $telerik.$(gridElement).find('div[id$=_Frozen]').get(0); // <div id="RadGrid1_Frozen"></div>

        if (!event.shiftKey) {
            if (cellIndex == numColumns) {
                // Reset scroll position to left edge
                frozenScroll.scrollLeft = 0;
            }
        }
        else {
            // Reduce the scroll position by the current cell's width
            frozenScroll.scrollLeft = frozenScroll.scrollLeft - currentCell.offsetWidth;
        }
    }
}


 

Regards,
Attila Antal
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Tags
Grid
Asked by
Thomas
Top achievements
Rank 1
Iron
Iron
Answers by
Thomas
Top achievements
Rank 1
Iron
Iron
Attila Antal
Telerik team
Share this question
or