I was watching Matthew Podwysocki event on https://www.youtube.com/watch?v=zlERo_JMGCw 29:38
Where he explains how they solved scroll on netflix. Where user scroll for more data as previous data gets cleaned up and more adds up (but scroll back shows previous data again).
I wanted to do similar, but I grabbed netflix demo code:
function getRowUpdates(row) {
var scrolls = Rx.Observable.fromEvent(document, 'scroll');
var rowVisibilities =
scrolls.throttle(50)
.map(function(scrollEvent) {
return row.isVisible(scrollEvent.offset);
})
.distinctUntilChanged();
var rowShows = rowrowVisibilities.filter(function(v) {
return v;
});
var rowHides = rowrowVisibilities.filter(function(v) {
return !v;
});
return rowShows
.flatMap(Rx.Observable.interval(10))
.flatMap(function() {
return row.getRowData().takeUntil(rowHides);
})
.toArray();
}
But I'm bit confused on how to pass new data or page data according to the scroll here.. Can someone give little explanation on how I can do the following:
fetch first list (I can do that)
fetch more list as user scroll down (using paging next page)
remove previous fetched data from memory, and refetch on request (scroll up).
Here is how I would do it in general lines. If this seems to give you satisfaction, I'll edit and add more details.
Version 2 : (For first one, see edit changes)
Premises :
The tag containing the dynamic list will be called "the zone".
Each row of the list will be contained in another DIV which can contains anything.
A page is enough rows to cover the zone.
Three javascript "constants" : numberOfLinesOnFirstLoad, numberOfLinesOnPageLoad, numberOfLinesToLoadAfter
JavaScript variables to hold required data : rows[page#], heights[page#], currentPageNumber = 1, maxPageNumber = 0
page# : # is the page number
rows[page#] shall contains a way to get them back from database, not real DOM objects.
Steps / Events :
Add the zone tag.
Load numberOfLinesOnFirstLoad rows.
If total rows height inferior zone height multiplied by three, then load numberOfLinesToLoadAfter rows. Repeat step 3 if rows added, otherwise continue to step 4.
maxPageNumber +=1. Find the next rows that full fills the zone. Add those rows to rows["page" + maxPageNumber] (as an array). Calculate the height of those and add it in heights["page" + maxPageNumber].
Repeat step 4 until no more rows and then continue to step 6.
When scrolling down and page1 (which means last element of rows["page1"]) is not visible, add another below : page4.
maxPageNumber += 1. Load numberOfLinesOnPageLoad rows.
If total new rows height inferior zone height, then numberOfLinesToLoadAfter rows. Repeat step 8 if rows added, otherwise put total new rows height in heights["page" + maxPageNumber] and the new rows as array in rows["page" + maxPageNumber] and continue to the step after entering this one (so either 9 or 11).
Still scrolling down, if page2 is not visible, remove the page1 elements from DOM and adjust scroll position by removing page1.height (heights["page1"]).
Load page 5 (step 7 and 8).
So now, there is page2 to page5 in the zone which page2 and page5 are not visible. If page3 is fully visible, than page4 is not, otherwise a part of page3 and page4 are visible. (Just to indicate possibilities, but not important)
When scrolling up and page2 is starting to be visible (so last element of rows["page2"]), load page1 by using rows["page1"], add page1.height (heights["page1"]) to scroll position and remove page5 from DOM. Here you can either remove it from variables rows && heights and maxPageNumber -= 1, but you can also keep them so that reloading this page is done in one process (so loading a page would imply to check if page definition already exists in those variables).
Related
When Array Element Update Use Socket.io then Page Scrolled Down in Angular 7. Please Tell How to stop page scroll down in like event.
this.socket.on(discussion.id, (reponse: any) =>
{
for (const [index, discussion] of this.discussionList.entries()) {
if (reponse.data.id == discussion.id)
{
reponse.data.displayComment = discussion.displayComment;
this.discussionList[index] = reponse.data;
console.log('Updated');
break; //Stop this loop, we found it!
}
console.log('finding....');
}
});
You basically updating some random item in array which is rendered as list. Of course your list will change content and new content can appear in current view. Its how html in browser works - nothing related to "Angular 7". Scroll not changed - changed what is visible in current scroll.
What you want to do is plain JS madness:
Before updating array 'remember' what was visible in current scrolled view. For example you read scrollTop and they loop over each item in list and check it's offset from top - closest to scrollTop is win.
After list updated find that element and scroll back to it.
It is messy, heavy for performance but thats a price of changing random piece of html on page.
I have a vuetify data table where I would like to keep the current page it is on when I change the rows per page number. It doesn't seem to trigger the pagination sync whenever I change rows per page. (The pagination sync should handle keeping track of which page as it works for other filters on the page e.g. when sorting the records, it will stay on the current page). Is this just how v-data-table works when changing rows per page?
Any help would be appreciated. Thanks
It's not clear what you mean by "same page." If there are 100 total rows in your table, and you are displaying 10 rows per page, and you are currently viewing rows 31-40 (i.e. "page 3"), and you switch to 50 rows per page, what page should you be on? With the new rows-per-page, there will only be 2 total pages, so being on "page 3" would be meaningless. If you switched to 5 rows per page, then items 31-35 would be on page 7 and items 36-40 would be on page 8. Which page should be displayed?
Since there is no clear, unambiguous definition of "same page," Vuetify defaults to returning to the first page as a sensible behavior.
However, for sake of argument, let's decide that by "same page" you mean that whatever item was on the first row of the table before you changed the items per page will remain visible on the screen after the items per page change. Obviously, if the number of items per page is decreased, e.g. goes from 10 to 5, you can't display ALL of the items that were on screen before the change.
Here's a demo of this in action on Codepen.
v-data-table has a #pagination event that fires every time the page changes, both when clicking through the pages, and when the number of items per page changes. The event handler receives an object that looks like this:
{
"page": 5, // 1-based index, i.e. first page is 1 (not zero)
"itemsPerPage": 5, // current items per page
"pageStart": 20, // 0-based index of the first item displayed on the screen
"pageStop": 25, // 0-based index of the first item on the *next* page
"pageCount": 20, // total number of pages
"itemsLength": 100 // total number of rows
}
We can store these values for later use, including updating the current page when the number of items per page changes.
First, you'll need to add two props to your v-data-table:
<v-data-table
:headers="headers"
:items="items"
:items-per-page="5"
:page.sync="pagination.page"
#pagination="updatePage"
></v-data-table>
page.sync allows you to programmatically set the current page, i.e. keep it in sync with a specified data prop. #pagination allows you to specify a function to receive and handle the pagination info whenever it changes. The script section of your component would look like this:
export default {
name: 'MyComponentWithADataTable',
data () {
return {
headers: [ /* ...data table header info... */ ],
items: [ /* ...the actual data in the table... */ ],
pagination: {}, // <-- holds our pagination data
}
},
computed: {
firstItem () {
// the index of the item that is the top row displayed on the screen
return this.pagination.pageStart
},
itemsPerPage () {
// the current number of items per page
return this.pagination.itemsPerPage
},
},
methods: {
updatePage (pagination) {
// detect change in itemsPerPage
if (this.itemsPerPage !== pagination.itemsPerPage) {
for (let p = 0; p < pagination.pageCount; p++) {
// figure out the page bounds
const start = p * pagination.itemsPerPage
const end = start + pagination.itemsPerPage
// is the target item on this page?
if (this.firstItem >= start && this.firstItem < end) {
// yes, so set the page to this page
pagination.page = p + 1
// break out of the loop
break;
}
}
}
// update the pagination info
this.pagination = pagination
}
},
}
I have a page that builds a table using DataTables, and each row has an Action Button that adds some data (an ID, just an int) from that row to a list. To keep users from clicking each action button multiple times, I made it so a row's button is removed the first time you click it. This worked great until I realized the buttons come back if you switch to the next page of the table and then switch back to the first page.
To fix this, I wrote some JS to compare each row to my list of data, and if that row's data is already in the list, it removes that row's action button. This happens each time the table is reloaded (for example, when you switch to a different page of the table and back again) using DataTable's draw.dt function.
The problem is, when I switch pages and the JavaScript goes to work removing buttons, for some reason it skips every other row. For example, if I click (thus removing) the first three rows' action buttons, switch pages and switch back, my JS removes the action buttons on row 1, 3, and 5 instead of rows 1, 2, and 3. It's so consistent that it has to be some kind of simple looping error due to my sloppy JS skills, but I can't find it.
Here is the code:
$(document).on('draw.dt', function () {
var $allSerialNumbers = $('.box-electrode'); // This is a list of all the rows' action buttons / ID's
$('#electrodes li').each(function (i, li) { // This is the list of ID's I'm comparing to
var $id = $(li).data('id');
for(var index = 0; index < $allSerialNumbers.length; index++){
if($id == $allSerialNumbers.eq(index).attr('data-id')){ // For each item in my ID list, run through all the rows and see if any Action Button ID's match any on the list
$('.box-electrode').eq(index).remove(); // If they do match, remove that Action Button
}
}
})
});
I'm not an expert on JQuery, but could remove() in your last line be re-sizing the list so that the element which used to be at index 1 is now at index 0, causing you to skip it when you increment the index?
Now, I am working with jQuery DataTable. Everything is going well in intializing data tables with javascript data array.
In my table, it included remove row button. When I clicked the Remove button of each row, I delete record using following function.
function removeRow(itemList, recordIndex){
itemList.splice(recordIndex, 1);
dataTable.clear();
dataTable.rows.add(itemList);
dataTable.columns.adjust().draw(false);
}
This function performed well with no error. At that, I set false to draw() function to prevent going to first page when delete records in any other page.This one also working for me.
The problem is, when my itemList has 11 records, and I go to second page of data table and delete the 11th record.
So, my itemList will left only 10 record and My data table should show the first page of paging.
But, jQuery data table is not doing that. It still have in second page with no records.
I don't know how to fix that one. I want to show previous page after delete every records from current page.
I know `draw()`` function without false parameter will go to first page. But it go to first page in every deletion.
I only want to go to previous page, when I deleted all records from current page.
Please, help me. Thanks.
I found an hacky way to get the previous pagination when the current has been emptied.
It is specific to jQuery DataTable, since using it's class naming.
Try it in CodePen.
function removeRow(recordIndex){
// Get previous pagination number
var previousPagination= parseInt( $(document).find(".paginate_button.current").data("dt-idx") ) -1;
// Splice the data.
data.splice(recordIndex,1);
myTable.clear();
myTable.rows.add(data);
myTable.columns.adjust().draw(false); // May ajust the pagination as empty... `.draw(false)` is needed.
// Decide to redraw or not based on the presence of `.deleteBtn` elements.
var doIdraw=false;
if($(document).find(".deleteBtn").length==0){
doIdraw=true;
}
myTable.columns.adjust().draw(doIdraw); // Re-draw the whole dataTable to pagination 1
// If the page redraws and a previous pagination existed (except the first)
if(previousPagination>1 && doIdraw){
var previousPage = $(document).find("[data-dt-idx='" + previousPagination + "']").click();
}
// Just to debug... Console.log the fact that only one pagination is left. You can remove that.
if(previousPagination==0 && doIdraw){
}
}
Notice that I used:
#myTable as the table id
.deleteBtn as the delete buttons class
data as the dataTable data
I removed all console.log() and example related code in the code above (but not in CodePen).
"Delete this →" button handler is:
$("#myTable").on("click",".deleteBtn",function(){
var rowElement = $(this).closest("tr");
var rowIndex = myTable.row(rowElement).index();
removeRow(rowIndex);
});
recently i am adding a Google table chart to my project. my task is to add a numeric pager in it. but i only can add
options['pagingSymbols'] = {prev: 'prev', next: 'next'};
options['pagingButtonsConfiguration'] = 'auto';.
it only shows next and previous button. so how can i change it to numeric paging. thanks in advance.
You would have to create a custom event handler for your chart. For instance, you can use a dataView to get 10 rows of data as follows:
var dataView = new google.visualization.DataView(data);
var page = 1;
dataView.setRows(page * 10 - 9,page * 10);
You can then create buttons in any way you'd like (images, etc.) below the chart, and attach an event to each of them. You can have that event show the page number in between, and then when you click the < or > buttons, it will change the page and the number through a function call, such as:
page = page + 1; // Obviously -1 for the minus button
dataView.setRows(page * 10 - 9,page * 10);
Then you'd write the 'page' to your document where the page number exists. You can do a current/max page value by looking at the max rows of data using:
var maxPage = data.getNumberOfRows();
Then you can write some sort of an error trapping function (for if they click "back" on the first page, or try to move to "next" on the last page). Or you can grey out the buttons. Or you can have it loop to the last page. Or whatever.
Whenever you make a change, you just redraw the table using your dataView instead of the actual data.