Telerik blogs

You can move any row into the user’s view screen (and save the user scrolling to find it) using the KendoGrid scrollToItem method.

It’s probably too obvious to mention, but: When your user is working with a Graphical User Interface (like, for example, a webpage) you’re mandated to get everything the user needs on the screen.

If you have a grid that has more rows than will fit on the screen, that mandate boils down to getting “the row the user wants” onto the screen, ideally without forcing the user to scroll-and-scan to find it.

In many of the Progress Kendo UI Grids, the scrollToItem method lets you get the row you or the user wants onto the screen, just by asking for the object the user wants. Using scrollToItem, you can pull a row that’s part of the grid’s page but not currently visible onto the screen, pull a row already on the screen to the top of the grid, or (in many cases) even pull rows not in the grid’s current page onto the screen. Your users, rather than having to scroll to find the item they want, can jump straight to it or you can put a row you know your user needs to see onto the screen.

The scrollToItem method is available in the KendoGrid for Angular, ASP.NET MVC and jQuery.

While the React Data Grid and the Blazor Grid don’t have scrollToItem, you can get some of the same behavior by accessing a row’s underlying HTML <tr> element and using the DOM’s scrollIntoView method … but the Kendo scrollToItem method is simpler to use and, even better, ties into your data model rather than the page’s HTML. The only real limitation on scrollToItem is that it doesn’t work with grouped paging.

Configuring the Project

To demonstrate using scrollToItem, I used the KendoGrid for ASP.NET MVC in an ASP.NET Core 8 Razor Page project. My first step was to add the Telerik.UI.for.AspNet.Core and Microsoft.AspNetCore.Mvc.NewtonSoft.Json NuGet packages to my project. After that, in the project’s Program.cs file, I added these statements before the builder.Build() statement:

builder.Services.AddKendo();
builder.Services.AddMvc().AddNewtonsoftJson(options =>
   options.SerializerSettings.ContractResolver =
    new DefaultContractResolver());

I generated a List of Product objects for my grid to display in an action method in an action method I called Get in a controller I called ProductsManager. To support retrieving data from my grid through that action method, I also added this statement after the Program.cs file’s builder.Build() statement:

app.MapControllers();

To complete configuring the project, I added these <link> and <script> tags to my project’s _Layout.cshtml file:

<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/ScrollItem.styles.css" asp-append-version="true" />
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/themes/12.0.1/bootstrap/bootstrap-main.css" />
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2025.3.1002/js/kendo.all.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2025.3.1002/js/kendo.aspnetmvc.min.js"></script>

Configuring the Grid

For my case study, I set up a grid with a very short window:

<kendo-grid name="productGrid" height="250">

</kendo-grid>

Inside that kendo-grid element, I nested a datasource element that would retrieve 20 rows into that short space, so that I’ll have lots of rows in the grid’s page that weren’t “on the screen” to play with. Inside the datasource element, I put a schema element, with a model element inside it.

That model element is key to having the scrollToItem method work: Users can ask for a row in the grid to be displayed by using the property specified in the model element’s id attribute. The property you use here must be unique for each row on the page so, nine times out of ten, the property you pick is going to be the property on your object’s that holds the corresponding table’s primary key.

In my case, for the Product object I’m displaying in each row of my grid, I used the object’s ProductID property:

<datasource type="DataSourceTagHelperType.Ajax" page-size="20">
  <schema>
    <model id="ProductID">
    </model>
  </schema>

The scrollToItem method works as long as scrolling is enabled for the grid, in either of the grid’s virtual or endless scrolling modes.

That means that you don’t need to include a scrollable element in your grid’s definition (the defaults are fine), but, if you do include the element:

  • If the enabled attribute is present, it must be set to true
  • If either of the virtual or endless attributes are present, at lest one of them must be set to true

Inside the datasource element, you’ll also need a transport element to specify where your data is coming from. (I used the Url object’s Action method to call my Get action method in my ProductsManager controller.):

  </schema>
  <transport>
    <read url='@Url.Action("Get", "ProductsManager")'  />
  </transport>
</datasource>

Following the datasource element, you define the columns you want displayed in the grid (and you don’t need to include the column that you’ll use to pull the right row onto the screen):

<columns>
  <column field="ProductName" title="Name" />
  <column field="Category" title="Category" />
  <column field="Price" title="Price" />
</columns>

Using scrollToItem

With all of that in place, you can write some JavaScript code to pull a row onto the screen. For this case study, I added a textbox to allow the user to enter the ProductID of the item they wanted to pull onto the screen. In the textbox’s onblur event I called a function I named MoveToItem, passing a reference to the textbox to that function:

<br/>
<input onblur="MoveToItem(this)" />
<br />

To support calling the grid’s scrollToItem method, I need a reference to the grid. In any real application, I’ll probably need that reference multiple times so, rather than keep retrieving that reference, I declared a global variable to hold the reference and loaded that variable from a jQuery onready function:

<script>
    let grid;
    $(() => {
        grid = $("#productGrid").kendoGrid();
    });

Below that function, I added my MoveToItem function. In that function, I called the grid’s scrollToItem method, passing the method the value property of the textbox I passed to the function (after checking that the textbox has something in it value property, of course):

const MoveToItem = (txt) => 
{
    if (txt.value)
    {
        grid.scrollToItem(txt.value);
    }
};

When that command executes, the row with the matching ProductID becomes the top row in the grid (assuming there are enough rows to fill the rest of the grid—if there aren’t enough rows, the grid will display the last rows in the grid, including the row with the matching ProductID).

Fetching New Data

That is, as long as the user passes a valid ProductID or that ProductID is on the current page. What do you do when that isn’t true?

The best solution for ensuring only valid ProductIDs are passed to your function is, of course, to have the user select a ProductID from a dropdown list rather than entering whatever they want into a textbox. A dropdown list would also let the user select a product name from the dropdown list but allow you to pass a ProductID to your function.

A typical dropdown list would look like this:

<select onchange="MoveToItem(this)">
  <option value="top">Select a product</option>
  <option value="A1">Chai Tea</option>
 ...

And the JavaScript function to work with it would look like this:

const MoveToItem = (sel) => {
  alert(sel.value);
  grid.scrollToItem(sel.value);
}

But what if, for some reason, a dropdown list isn’t an option or the user’s entry is valid but the object isn’t in the grid’s current page? Provided you have virtual scrolling enabled, you can handle both of those scenarios by passing a callback function as the second parameter to the scrollToItem method.

The callback function is only called if scrollToItem can’t scroll to the item specified in its first parameter. So, for the “invalid choice” scenario, you can use that callback function to provide an error message. Basic code would look like this:

const MoveToItem = (txt) => 
{
  if (txt.value)
  {
    grid.scrollToItem(txt.value, 
 	 	  function () { 
        if (<…check for invalid value…>) 
        {
          alert("Invalid ProductID: " + txt.value);
        }
      }
    );
  }
}

However, that callback function is also passed an object that you can use to pull a row not in the current grid page onto the screen … provided you know the row’s position in your virtual list. All you need to do (after you determine the row’s position in your virtual list) is pass the row’s position to the object’s success method.

This sample code doesn’t attempt to find the right object that but just pulls the first row back onto the screen when the requested object isn’t found on the current page:

const MoveToItem = (e) => 
{
  if (e.value)
  {
    grid.scrollToItem(txt.value, 
      function (o) { 
        if (<…check for invalid value…>) 
      {
        alert("Invalid ProductID: " + txt.value);
      }
      else
      {
        o.success(1);
      }
    }
  }
}

In a GUI, your first goal is to provide your user whatever they need right in front of them. The scrollToItem method is the tool that enables you to do that while letting the user jump straight to the row they want.


Explore all the grids Progress provides with a free 30-day trial of the Progress Telerik DevCraft bundle:

Try Telerik DevCraft


Peter Vogel
About the Author

Peter Vogel

Peter Vogel is both the author of the Coding Azure series and the instructor for Coding Azure in the Classroom. Peter’s company provides full-stack development from UX design through object modeling to database design. Peter holds multiple certifications in Azure administration, architecture, development and security and is a Microsoft Certified Trainer.

Related Posts

Comments

Comments are disabled in preview mode.