We have a large data grid with virtual scrolling (needed for performance), all data on client (server operation = false).
This is a big list of parts.
What is the best way to allow the user to scroll to a part number that is currently not rendered in the grid?
10 Answers, 1 is accepted
Nothing?
We are getting close to getting excel type functionality on a web grid with a large dataset. But missing a few key elements. Including this.
Currently, the Grid does not provide a feature to scroll to a specific item.
I can suggest using a filter mode row, and allow the user to search for the specific part number.
http://docs.telerik.com/kendo-ui/api/javascript/ui/grid#configuration-filterable.mode
Also, I can suggest submitting a feature request and based on its popularity we may implement it in a future release:
http://kendoui-feedback.telerik.com/forums/127393-kendo-ui-feedback/category/170280-grid
Another option will be our Feature acceleration program which will allow purchasing a specific feature, which is not on our roadmap, but it is very important for the application.
Regards,
Stefan
Progress Telerik
Thanks, I'll see how this works.
I added a feature request. 8 years ago I wrote the line of code below in a silverlight radgrid and was able to achieve this, it would be nice to do in a kendo grid as easily.
PartGridView.ScrollIntoView(item);
As an update to your report, simply filtering to the row the user is searching for is not an acceptable solution, because they need to see the row in the context of its parent and/or child rows which of course disappear with filtering.
Hopefully I can find another solution.
The developers will look into the feature request you have submitted and will consider the possibilities for implementing it based on the traction it gets with the community.
With that said, if the feature is crucial to your application you can consider our Feature Acceleration service. It enables you to negotiate a certain functionality to be implemented sooner.
Regards,
Viktor Tachev
Progress Telerik
Ok, well it possible to write a custom javascript search function that would:
1. Find the part in question in the grid datasource
2. Analyze the position of the dataitem in relation to the entire datasource
3. Calculate the page based on the page size and position of dataitem
4. grid.wrapper.find(".k-scrollbar").scrollTop to the new page
5. Perhaps highlight or do a css fade function on the part that was found since it may not be exactly on the top of the page
Let me know if this approach is possible, and I will write it. Thanks
Due to some of the specifics of the Virtual scrolling, this approach may not work as expected, because when the page is changed the DOM elements are replaced with the ones for the new page. This will result in the page with the searched item not being rendered, so the Grid will not scroll to it as it is not part of the DOM.
Regards,
Stefan
Progress Telerik
Per your post, this is partially working. On the server I've given all the items in my data a page number based on the page size of the grid.
I then find all matching items in the grid.
var grid = $("#grid").data("kendoGrid");
var data = grid.dataSource._data;
var matchingParts = $.grep(data, function (d) {
return d.PartNumber.indexOf(partNumber) === 0;
});
Then allowing the user to iterate through all the items by determining the page number each item and scrolling to that page.
var pageNumber = matchingPart.PageNumber;
var rowHeight = grid.tbody.children().eq(0).height();
var pageSize = grid.dataSource.pageSize();
var scrollTop = rowHeight * pageSize * (pageNumber - 1);
grid.wrapper.find(".k-scrollbar").scrollTop(scrollTop);
This will render the proper 'page' (effect of scrolling), but the actual item may not be in the viewable area.
Is there any way once the virtual page is rendered, to center the item that was searched for?
If so, this approach would be workable for me.
I'm glad to hear that the desired result is almost achieved.
In general, the provided logic to scroll the Grid should works as expected. I can assume that some modification of the variables may be needed. I made a test scenario and it was working as expected:
http://dojo.telerik.com/AYoPa
Also, we recommend using the data method of the dataSource instead of the private _data variable:
https://admin.telerik.com/docs.telerik.com/kendo-ui/api/javascript/data/datasource#methods-data
Regards,
Stefan
Progress Telerik
I'll post my current solution in case it helps someone, or someone wants to improve it. I basically calculate the offset by calculating the page number and index number (per 100 records). Then scroll to the row and highlight it. If the scroll is going to a new page, then the databound event handler highlights the row after it's been rendered.
I'm using a constant (18.6), since it's more exact than multiplying the row height (19px). I suppose this could be dynamically adjusted per the users zoom or other factors.
01.
var
searchedPartNumber;
// part number that is being searched for
02.
var
searchedPartIndex;
// the index of the array of parts currently being searched
03.
var
selectOrderNumber;
// the number of the row
04.
var
searchDataBound =
false
;
05.
06.
07.
function
onGridDataBound(e) {
08.
if
($(
"#partNumberSearchInput"
).val() && searchDataBound) {
09.
setTimeout(
function
() { selectRow($(
"#partNumberSearchInput"
).val()); }, 200);
10.
}
11.
}
12.
13.
function
searchPartNumber() {
14.
searchDataBound =
true
;
15.
var
partNumber = $(
"#partNumberSearchInput"
).val().trim();
16.
if
(searchedPartNumber && (partNumber !== searchedPartNumber)) {
17.
searchedPartNumber = undefined;
18.
selectOrderNumber = undefined;
19.
searchedPartIndex = undefined;
20.
}
21.
22.
var
grid = $(
"#MyGrid"
).data(
"kendoGrid"
);
23.
var
data = grid.dataSource._data;
24.
var
matchingParts = $.grep(data,
function
(d) {
25.
return
d.PartNumber.indexOf(partNumber) === 0;
26.
});
27.
28.
if
(matchingParts.length > 0) {
29.
var
matchingPart;
30.
if
(matchingParts.length === 1) {
31.
matchingPart = matchingParts[0];
32.
}
else
{
33.
searchedPartNumber = partNumber;
34.
if
(searchedPartIndex === undefined) {
35.
searchedPartIndex = 0;
36.
}
else
{
37.
searchedPartIndex++;
38.
}
39.
if
(searchedPartIndex > matchingParts.length - 1) {
40.
searchedPartIndex = 0;
41.
}
42.
matchingPart = matchingParts[searchedPartIndex];
43.
}
44.
45.
var
pageNumber = matchingPart.PageNumber;
46.
selectOrderNumber = matchingPart.OrderNumber;
47.
var
orderNumber = selectOrderNumber.toString();
48.
49.
if
(orderNumber.length > 1) {
50.
orderNumber = orderNumber.substr(orderNumber.length - 2);
51.
}
52.
53.
var
orderNumberInt = parseInt(orderNumber, 10);
54.
var
numberOffset = (orderNumberInt - 1) * 18.6;
55.
var
scrollTop = (1860.65 * (pageNumber - 1)) + numberOffset;
56.
grid.wrapper.find(
".k-scrollbar"
).scrollTop(scrollTop);
57.
if
(pageNumber === grid.dataSource._page) {
58.
selectRow(partNumber);
59.
}
// else called on databound
60.
61.
if
(!searchedPartIndex) {
62.
searchedPartIndex = 0;
63.
}
//recycle back to start of search
64.
65.
$(
"#searchInfo"
).html((searchedPartIndex + 1) +
" of "
+ matchingParts.length +
", Line Number: "
+ selectOrderNumber);
66.
}
else
{
67.
alert(
"Could not find part number "
+ partNumber +
" in this list"
);
68.
}
69.
}
70.
71.
function
selectRow(partNumber) {
72.
searchDataBound =
false
;
73.
if
(partNumber) {
74.
var
grid = $(
"#MyGrid"
).data(
"kendoGrid"
);
75.
var
rows = grid.tbody.find(
" > tr"
);
76.
var
rowCount = grid.tbody.find(
" > tr"
).length;
77.
if
(rowCount > 0) {
78.
for
(
var
x = 0; x < rowCount; x++) {
79.
var
dataItem = grid.dataItem(rows[x]);
80.
var
row = rows[x];
81.
if
(dataItem.PartNumber === partNumber) {
82.
row.style.backgroundColor =
"#b9f6ca"
;
83.
}
84.
}
85.
}
86.
}
87.
}