10

I want to be able to call a function that scrolls the Kendo grid to the selected row. I´ve already tried some methods but none of them worked,

for instance I tried this:

var grid = $("#Grid").data("kendoGrid"),
    content = $(".k-grid-content");
content.scrollTop(grid.select());

I´ve also tried this:

var gr = $("#Grid").data("kendoGrid");
var dataItem = gr.dataSource.view()[gr.select().closest("tr").index()];
var material = dataItem.id;
var row = grid.tbody.find(">tr:not(.k-grouping-row)").filter(function (i) {
    return (this.dataset.id == material);
});
content.scrollTop(row);

Can anyone point me in the right direction please? :)

--- EDITED ---

For other reasons I can not bind to the change event so I have to be able to call a function the scrolls the list to the selected row. This is what I tried with the answer @Antonis provided for me.

var grid = $("#Grid").data("kendoGrid")
grid.element.find(".k-grid-content").animate({  
    scrollTop: this.select().offset().top  
 }, 400);

When I tried this it scrolled somewhat down the list but not to the selected row. Am I use the grid object in a wrong way by calling scrollTop on it?

This too:

var grid = $("#ItemGrid").data("kendoGrid");
grid.scrollToSelectedRow = function () {
    var selectedRow = this.select();
    if (!selectedRow) {    
        return false;    
    }
    this.element.find(".k-grid-content").animate({
        scrollTop: selectedRow.offset().top  
    }, 400);
    return true;
    };

grid.scrollToSelectedRow();
gardarvalur
  • 1,565
  • 9
  • 39
  • 65
  • 1
    `scrollTop()` takes an integer parameter as the offset in pixels from the top, not an element to scroll to. For example `.scrollTop(0)` would scroll to the top (0 pixel offset from the top). – CodingWithSpike Jul 03 '13 at 17:56

6 Answers6

16

So most of the answers here are making two mistakes, one just a matter of efficiency, the other an actual bug.

  1. Using element.find(".k-grid-content"). This is just massively unnecessary. grid.content gives you the exact same thing much more easily (and more quickly).

  2. Using .offset() to find the position of the row. This is incorrect: that will tell you the row's position relative to the document itself. If your page allows you to scroll the entire page (not just the grid), this number will be incorrect.

    Instead use .position() – this gives you the position relative to an offset parent. In order for .position() to give you the correct numbers, the table in your grid.content must have position: relative. This is best applied through a CSS style sheet:

    .k-grid-content table {
      position: relative;
    }

Anyway, assuming you already have a reference, which I'll call grid, to the grid itself, and you have your content pane set to relative position, all you have to do is this:

grid.content.scrollTop(grid.select().position().top);

Or, for animation,

grid.content.animate({ scrollTop: grid.select().position().top }, 400);

As already discussed, grid.content gets you the content pane, the part you want to actually scroll. It is a jQuery object.

jQuery objects have a .scrollTop method, so that part is pretty simple. The .animate method works similarly when you use its scrollTop property. Now we just need to know where to scroll to.

For that, grid.select() returns a jQuery object corresponding to the row that is selected. That's where you want to scroll to. To get its position, we use the jQuery .position() method. The return value is an object with top and left fields; we want to scroll to its vertical position, so we use top.

This is most easy to use in the change callback, of course; there grid is simply this (since the callback is called on the grid itself), and change is automatically called when the selection changes. But you can call this code any time you want to scroll to the selection; you can get grid by using:

grid = $('#theGridsId').data('kendoGrid');
damd
  • 6,116
  • 7
  • 48
  • 77
KRyan
  • 7,308
  • 2
  • 40
  • 68
6

You can do it automatically when a row is selected. Bind a function to the 'change' event, and in there, you can scroll to the selected row. ( assuming you can select only one row, which is given by the 'this.select()' )

JSFiddle example

the 'change' handler

//    bind to 'change' event
function onChangeSelection(e) {

    //    animate our scroll
    this.element.find(".k-grid-content").animate({  // use $('html, body') if you want to scroll the body and not the k-grid-content div
        scrollTop: this.select().offset().top  //  scroll to the selected row given by 'this.select()'
     }, 400);
}
AntouanK
  • 4,880
  • 1
  • 21
  • 26
  • Thank you for your answer @Antonis. I´ve edited my question according to your answer. The problem is that I can not use the change-event for other reasons. I need to be able to call the grid and then scrollto the selected element. – gardarvalur Jul 04 '13 at 10:33
  • Ok, you can definitely do this. I'll try to find some free time and make you an example. But you can try yourself, just see how I did it. You have to get first the selected row, and then scroll to it. – AntouanK Jul 04 '13 at 10:43
  • 1
    see a quick example. I made a button which calls the scroll function whenever you click it --> http://jsfiddle.net/blackjim/9GCYE/12/ The scrolling has a little bug. Try to fix it with a debugger in the `scrollToSelectedRow` function. Unfortunately I don't have much time to fix it now. – AntouanK Jul 04 '13 at 12:08
  • Thanks for that example, I see it works correctly in jsfiddle. I´ve implemented the new scroll function for the grid like in your example. I receive no errors but it´s not scrolling yet. I´m wondering about the "kendoScroller" in the last line of the example, for some reason my compiler will not accept it as a known function. Is that a vital property for the scroller to work? – gardarvalur Jul 04 '13 at 12:45
  • no, delete this line. I don't remember if I wrote it. Maybe I was trying something and I forgot it. – AntouanK Jul 04 '13 at 12:51
  • I finally got it to work by using your example in jsfiddle. For those who are wondering I used the sortToSelectedRow(grid) function and changed 'this' for 'grid'. Now it finally animates the scrolling :) Thank you for your great help @Antonis ! – gardarvalur Jul 04 '13 at 13:10
  • glad it worked. But it's strange you had to fix this. When you call it like this `grid.scrollToSelectedRow();` `this` refers to the `grid`. Maybe I missed something... – AntouanK Jul 04 '13 at 13:15
  • No you didn´t miss anything, I think I did ;) The strange thing is that this scrolls only some of the times. I may need to check my code or even create a new issue here on stackoverflow later. Your code should of course work since you are basically writing the same function but just adding it to the grid. Anyway, this issue is somewhat resolved, I just need to verify my code a little bit. – gardarvalur Jul 04 '13 at 13:25
  • `element.find(".k-grid-content")` is ridiculously inefficient; use `.content` instead. – KRyan Feb 23 '15 at 22:36
  • Also, using `.offset()` is simply **wrong**; that is not the number you want. `.position()` is the one you want, but **only** if you apply `position: relative;` to the `grid.content` (or to `.k-grid-content` through CSS). – KRyan Feb 23 '15 at 23:06
0

Here is the updated code http://jsfiddle.net/27Phm/12/

//    bind to 'change' event
function onChangeSelection(e) {
    try {
        var $trSelect = this.select();
        var $kcontent = this.element.find(".k-grid-content");
        if ($trSelect && $trSelect.length == 1 && $kcontent) {
            var scrollContentOffset = this.element.find("tbody").offset().top;
            var selectContentOffset = $trSelect.offset().top;
            var IsMove = false;
            var distance = selectContentOffset - scrollContentOffset;
            distance += $kcontent.offset().top;
            if ($trSelect.prev().length == 1 && distance > $trSelect.prev().offset().top) {
                distance = (distance - $trSelect.prev().offset().top); //+ ($trSelect.height());
                //var toprows = $kcontent.scrollTop() / $trSelect.height(); //top rows above the scroll
                var selrowtotal = ($trSelect.offset().top - $kcontent.offset().top) + $trSelect.height();
                IsMove = selrowtotal > $kcontent.height() ? true : false;
                if (IsMove) $kcontent.scrollTop(distance);
            }
            if (!IsMove && $trSelect.offset().top < $kcontent.offset().top) {
                distance = selectContentOffset - scrollContentOffset;
                $kcontent.scrollTop(distance - 15);`enter code here`
            }
        }
    } catch (e) {

    }
}
  • Seem like this line: if (IsMove) $kcontent.scrollTop(distance); should be: if (IsMove) $kcontent.scrollTop(selrowtotal - distance); – CharlesC Sep 08 '14 at 21:18
  • 1
    This problem can and should be solved in one line, two if you want to be extremely clear about what you're doing. – KRyan Feb 23 '15 at 22:36
0

I had problems with the offset so position works better for me:

grid.element.find(".k-grid-content").animate({  // use $('html, body') if you want to scroll the body and not the k-grid-content div
                    scrollTop: this.select().position().top  //  scroll to the selected row given by 'this.select()'
                 }, 400);    
acady
  • 21
  • 2
  • 1
    `element.find(".k-grid-content")` is ridiculously inefficient; use `.content` instead. – KRyan Feb 23 '15 at 22:35
0

I found a function for this, in Kendo mobile MVVM

parent.set('onShow', function (e) {
   e.view.scroller.reset();
}

or

app.xxx = kendo.observable({
   onShow: function() { e.view.scroller.reset(); }
});
Wagner Pereira
  • 1,050
  • 11
  • 11
0

In addition to what has been said, if you use virtual scroll e.g. JQuery:

$("#grid").kendoGrid({
scrollable: {
    virtual: true
}});

or in ASP.NET MVC

.Scrollable(scrollable => scrollable.Virtual(true))

..in this case it looks like kendo adds a special div on the right side just for the scroll with the class .k-scrollbar, so instead of element.find(".k-grid-content").scrollTop(distance) or grid.content.scrollTop(distance) like it was mentioned, we may use something like this to scroll to selected row:

const myGrid = $("#myGrid");
const scrollContentOffset = myGrid.find("tbody").offset().top;
const selectContentOffset = myGrid.select().offset().top;
const distance = selectContentOffset - scrollContentOffset;
myGrid.find(".k-scrollbar").scrollTop(distance);

I've struggled with this a bit so maybe it helps someone save some time.

Cristian Rusanu
  • 452
  • 5
  • 15