Author Topic: Lazy Loading scroll bar suggestion  (Read 239 times)

jplevene

  • Pro Ultimate
  • Jr. Member
  • *
  • Posts: 95
    • View Profile
Lazy Loading scroll bar suggestion
« on: May 01, 2024, 10:11:39 pm »
Using https://paramquery.com/pro/demos/infinite_scroll as an example, can we have an option (not compulsory as I like the current way as well) to make the scroll bar seem as if there are "totalRecords" in the grid instead of just the loaded ones.

Please do not remove the current way, just give an option to have these "empty rows" so that the scroll bar shows correctly.

May I suggest that if "totalRecords" is not passed then it uses the old method and bases the scroll bar on how many rows.

I have tried setting I tried setting "paging.rPP" and returning { "curPage:":response.curPage, "data":response.data, "totalRecords":response.totalRecords }, but it does nothing.

Issues and workflows I can see are:
  • The "curPage" number would always need to be sent and returned.
  • The "num_rows" per page would need to be sent and constant from the first page
  • If "totalRecords" is different to the initially returned number, then the out of view top and bottom virtual spacing would need to be changed accordingly to correctly draw the scroll bar.
  • If the view has been scrolled to fit between two pages, there needs to be a flag to make sure the grid waits for the first page to load before it loads a second ("pending" flag in the example).
  • Page loading of empty pages should only start when scrolling stops, and maybe also include a variable for how many milliseconds to pause before loading the next page starts after the scroll stop, which is reset if scrolling starts again within that time.

The
« Last Edit: May 01, 2024, 10:28:02 pm by jplevene »

paramvir

  • Administrator
  • Hero Member
  • *****
  • Posts: 6255
    • View Profile
Re: Lazy Loading scroll bar suggestion
« Reply #1 on: July 31, 2024, 04:28:27 pm »
Quote
can we have an option to make the scroll bar seem as if there are "totalRecords" in the grid instead of just the loaded ones.

You mean working like this example: https://paramquery.com/pro/demos87/virtual_scroll

jplevene

  • Pro Ultimate
  • Jr. Member
  • *
  • Posts: 95
    • View Profile
Re: Lazy Loading scroll bar suggestion
« Reply #2 on: July 31, 2024, 06:23:46 pm »
There is a slight issue.

Once loaded:
  • If I click CTRL+End, it scrolls to the end and only the last page loads, not the ones in between (only works on v8.7 and not v9)
  • If I drag the scroll bar down to the bottom, even really quickly, all the middle pages are loaded before the last page, meaning if a user does this with lets say 100 pages, 97 or 98 would load unecessarily.
« Last Edit: July 31, 2024, 06:55:57 pm by jplevene »

paramvir

  • Administrator
  • Hero Member
  • *****
  • Posts: 6255
    • View Profile
Re: Lazy Loading scroll bar suggestion
« Reply #3 on: July 31, 2024, 10:47:53 pm »
For that, scrollStop event can be used to fetch remote records as in this example:

https://paramquery.com/pro/demos/virtual_scroll

jplevene

  • Pro Ultimate
  • Jr. Member
  • *
  • Posts: 95
    • View Profile
Re: Lazy Loading scroll bar suggestion
« Reply #4 on: July 31, 2024, 10:49:28 pm »
Posts got crossed, just trying above

This is not working on v9.1.1 as the beforeTableView event is getting fired multiple times at once as multiple items come into view on a mouse scroll (for me it is 9 times).  On my computer, my variable grid_paging["pending"] is still false (Ryzen 5 PRO 5650 3.9GHz with 16GB ram, it's ok fast) using the code below:

Code: [Select]
//var grid = my jQuery grid <div>;

var grid_paging = {
init: function()
{
this.data = []; // All the data so far from the server
this.totalRecords = 0, // How many rows in total need to be loaded
this.curPage = 0; // Last page loaded (0 means nothing loaded as each request is page+1)
this.rowsPerPage = 100; // How many rows per page
this.pending = true; // Need to load next batch flag
}
};
grid_paging.init();
....
beforeTableView: function(evt, ui) {
var initV = ui.initV, // First visible row index
finalV = ui.finalV, // Last visible row index
data = grid_paging["data"],
rpp = grid_paging["rowsPerPage"],
requestPage = 0;

// Do we have a top index and is no load pending
if(initV != null && !grid_paging["pending"])
{
// Is the top row visible empty
if (data[initV] && data[initV]["pq_empty"])
requestPage = Math.floor(initV / rpp) + 1;
// Is the bottom row visible empty
else if(data[finalV] && data[finalV]["pq_empty"]) {
requestPage = Math.floor(finalV / rpp) + 1;
}

if(requestPage>=1 && grid_paging["curPage"]!==requestPage && !grid_paging["pending"])
{
// Even added this makes no difference
//grid_paging["curPage"] = requestPage;

// Prevent any further calls
grid_paging["pending"] = true;
// Set the current page
grid_paging["curPage"] = requestPage;
// Request more rows.
grid.pqGrid("refreshDataAndView");
//grid.pqGrid("hideLoading");
}
}
}
« Last Edit: July 31, 2024, 10:58:57 pm by jplevene »

paramvir

  • Administrator
  • Hero Member
  • *****
  • Posts: 6255
    • View Profile
Re: Lazy Loading scroll bar suggestion
« Reply #5 on: July 31, 2024, 10:55:25 pm »
no need to use beforeTableView event when using scrollStop event

https://paramquery.com/pro/demos/virtual_scroll

jplevene

  • Pro Ultimate
  • Jr. Member
  • *
  • Posts: 95
    • View Profile
Re: Lazy Loading scroll bar suggestion
« Reply #6 on: July 31, 2024, 11:12:50 pm »
Not working.  I'm now getting issues with grid.pqGrid("getXHR").abort(); and a console error saying "Cannot read properties of undefined (reading 'abort')"

If I remove the line of code, pqGrid code causes the same error below:

Code: [Select]
fn.remoteRequest = function(objP) {
objP = objP || {};
var that = this,
obj = that.getQueryString(objP),
url = obj.url,
dataURL = obj.dataURL;
if (that.loading) {
that.xhr.abort() // <<<<<<<<<<<<<<<< HERE
}
if (url) {
that.showLoading();
that.callXHR(url, dataURL, function(response, textStatus, jqXHR) {
that.onRemoteSuccess(response, textStatus, jqXHR, objP)
})
}
};

My data model is:

Code: [Select]
{
recIndx: "ID", // Key field
location: "remote", // Data source is remote 
url: "list.php", // URL of list
dataType: "JSON", // Data format
method: "GET", // GET or POST
getData: function(dataJSON, textStatus, jqXHR){ return that.grid_after_get_data(dataJSON, textStatus, jqXHR); }
}

grid_after_get_data is inside another object:

Code: [Select]
grid_after_get_data: function(dataJSON, textStatus, jqXHR)
{

var data = dataJSON.data,
len = data.length,
curPage = dataJSON.page,
init = (curPage - 1) * this.grid_paging["rowsPerPage"];

this.grid.pqGrid("hideLoading");

// First page and record count
if(dataJSON["page"]==1 && typeof(dataJSON["totalRecords"])!=="undefined")
this.grid_paging["totalRecords"] = intval(dataJSON["totalRecords"]);

//copy rows from remote response to grid data cache.
for (var i = 0; i < len; i++) {
this.grid_paging["data"][i + init] = data[i];
}
// Spoof the array into thinking x amount of rows
this.grid_paging["data"].length = this.grid_paging["totalRecords"];

return { data: this.grid_paging["data"] }
},
« Last Edit: July 31, 2024, 11:50:21 pm by jplevene »

jplevene

  • Pro Ultimate
  • Jr. Member
  • *
  • Posts: 95
    • View Profile
Re: Lazy Loading scroll bar suggestion
« Reply #7 on: July 31, 2024, 11:54:54 pm »
I did the following:

Code: [Select]
var xhr = this.grid.pqGrid("getXHR");
console.log(xhr);

In the console, xhr was the gid div element????

I also did:

Code: [Select]
grid = this.grid.pqGrid("instance"),
console.log(grid);

And in the console xhr is undefined which I don't understand as the first page was loaded??
« Last Edit: August 01, 2024, 12:02:13 am by jplevene »

jplevene

  • Pro Ultimate
  • Jr. Member
  • *
  • Posts: 95
    • View Profile
Re: Lazy Loading scroll bar suggestion
« Reply #8 on: August 01, 2024, 03:11:19 am »
I fixed it by doing a combination of things.  Also by moving grid.pqGrid("showLoading") after grid.pqGrid("refreshDataAndView") fixed the xhr error.

In your code you had
Code: [Select]
this.one('refresh', loadRemoteData.bind(this)); inside scrollStop  What was this for?

My code is below:

Code: [Select]
getData: function(dataJSON, textStatus, jqXHR)
{
var data = dataJSON.data ? dataJSON.data : [],
len = data.length,
curPage = dataJSON.page,
init = (curPage - 1) * grid_paging["rowsPerPage"];

grid.pqGrid("hideLoading");

// Already set in grid_scrollStop(), but just to make sure
grid_paging["curPage"] = intval(dataJSON["page"]);

// First page and record count
if(dataJSON["page"]==1 && typeof(dataJSON["totalRecords"])!=="undefined")
{
grid_paging["totalRecords"] = intval(dataJSON["totalRecords"]);
// Fill entire grid with empty records
grid_paging["data"] = Array(grid_paging["totalRecords"]).fill({pq_empty:true});
}

// Copy rows from remote response to grid data cache.
for (var i = 0; i < len; i++) {
data[i]["pq_empty"] = false;
grid_paging["data"][i + init] = data[i];
}

grid_paging["pending"] = false;

// Just incase between rows
if(len>0) setTimeout(function(){ grid_scrollStop(); }, 500);

// Return the data
return {
"data": grid_paging["data"]
};
},
scrollStop: function(){ grid_scrollStop(); }


Code: [Select]
function grid_scrollStop()
{
var ui = grid.pqGrid("getViewPortIndx"),
initV = ui.initV, // First visible row index
finalV = ui.finalV, // Last visible row index
data = grid_paging["data"],
rpp = grid_paging["rowsPerPage"],
requestPage = 0;

if(initV!==null)
{
// Is the top row visible empty
if (data[initV] && data[initV]["pq_empty"])
requestPage = Math.floor(initV / rpp) + 1;
// Is the bottom row visible empty
else if(data[finalV] && data[finalV]["pq_empty"])
requestPage = Math.floor(finalV / rpp) + 1;

// Do we have a request page, it is different from the current page and loading is still pending
if(requestPage>=1 && grid_paging["curPage"]!==requestPage)
{
if(!grid_paging["pending"])
{
// Prevent any further calls
grid_paging["pending"] = true;
// Set the current page
grid_paging["curPage"] = requestPage;
//cancel any previous remote request.
//grid.pqGrid("getXHR").abort();  // <<<<<<<<<< DOES NOT WORK HERE
var xhr = grid.pqGrid("getXHR");
if(xhr && typeof(xhr.abort)==="function") xhr.abort();
// Request more rows.
grid.pqGrid("refreshDataAndView");
// Show the loading
grid.pqGrid("showLoading");   // <<<<<<<<<< FINE IF AFTER refreshDataAndView
}
}
}
}

« Last Edit: August 01, 2024, 03:15:36 am by jplevene »

paramvir

  • Administrator
  • Hero Member
  • *****
  • Posts: 6255
    • View Profile
Re: Lazy Loading scroll bar suggestion
« Reply #9 on: August 01, 2024, 11:37:42 am »
Glad to know that it's finally working for you.

this.one('refresh', loadRemoteData.bind(this)); is used to fetch remaining rows if the viewport position is in between 2 pages, e.g. if records per page is 100, and viewport position is from 80 to 120, then first call to remote server fetch records from 0 to 100, and second one fetch records from 101 to 200.