I want to scroll to the bottom of a webpage using JS and, looking online, most people say to use
window.scrollTo(0,document.body.scrollHeight);
However the page I want to scroll down changes its height as you reach the bottom (it continuously loads more and more of the page) so its height is not fixed. The eventual height also varies (thus I cannot just scroll to the final height of the page) so I need some way of scrolling until it determines it has reached the bottom (it cannot scroll any further).
If you have infinite scroll, you actually need to incorporate that in your design. E.g. scrollToBottom should look like this:
function scrollToBottom(lastOffset) {
const offset = document.body.scrollHeight;
// check if no more scrolling required.
if (lastOffset === offset) {
return;
}
// if it is, go to bottom.
window.scrollTo(0, offset);
// Now, trigger your `loadMore` logic, whatever it might be, then call scrollToBottom again.
triggerLoadMore().then(() => scrollToBottom(offset));
// or triggerLoadMore(() => scrollToBottom(offset));
}
// call this somewhere after your initial load.
Now, triggerLoadMore, erm, triggers your loadMore logic. I included two versions in the above code, one being promise-based, the commented one being callback-based. It should call back your function (scrollToBottom) when it has loaded more and put it on the screen. How you do that, depends on what you use, and is possibly another question.
Now, there's a third option here, that your trigger is something that you cannot call directly, because it's tied to window.scroll event or some such logic. In that case, you need to write this bit of logic at the end of such function flow - load more, render on screen, scroll. Which then triggers the cycle again.
#Zlatko answer is the best performance. However, you can use this one in every context :
window.addEventListener( 'resize', function(){
window.scrollTo(0,document.body.scrollHeight);
});
Sounds like you need to reach bottom of the page, wait for load and scroll to bottom again. You can't reach the end of the page where you cannot know the end.
function scroll_and_wait(){
return new Promise(
function(resolve, reject){
setTimeout(function(){
resolve(window.scrollTo(0,document.body.scrollHeight));
}, 500);})}
async function scroller(n){while(n>0){await scroll_and_wait();n=n-1;}}
scroller(5)
Calling scroller function will scroll to to bottom of the page as many times as you specify with 500ms pause for loading.
Related
I have a HTML which is very long. I would like to auto-scroll the content on load. My requirements are:
Go to top when page opened.
Scroll to the utmost bottom.
Here's what I tried:
function pageScroll() {
window.scrollBy(0,7000);
scrolldelay = setTimeout('pageScroll()',1000);
}
This works well but I want it to be faster and also I would like a replacement of 7000.
These are the values which should work best in my opinion
function pageScroll() {
window.scrollBy(0, 3060) //don't set a timeout function
}
pageScroll()
I faced an issue during my project developing, it's related to a difference between getBoundingClientRect values with and without preventive break points during debugging. Trying to minimize repro, I got following.
const scrollHandler = () => {
setTimeout(() => {
const top = document.getElementById('test').getBoundingClientRect().top;
console.log(top);
});
};
document.getElementById('viewport').addEventListener('scroll', scrollHandler);
where the viewport is just scrollable div with fixed height. The content of the viewport is big enough to be able to fire at least one scroll event. I also created Plunker demo. All magic happens inside of setTimeout callback.
Now the steps. Success scenario.
Set break point at the beginning of the setTimeout callback.
Fire scroll event.
Make "step over" to obtain top value.
Execute document.getElementById('test').getBoundingClientRect().top in the console.
The results of 3 and 4 are the same.
Failed scenario.
Set break point at the end of the setTimeout callback.
Fire scroll event.
Get the value of top variable (no action is needed).
Execute document.getElementById('test').getBoundingClientRect().top in the console.
The results of 3 and 4 are not the same.
To avoid any misunderstanding with this repro, I recorded a short demo movie with the above steps.
In my project I'm doing calculations in a similar environment (throttled scroll events) and getting wrong results that don't match expectations. But when I debug it, I'm getting different picture; a preventive break point fixes calculations.
Is it a bug or known issue? Or did I miss something? should I refuse to use getBoundingClientRect in such a situation?
I'm not sure what it is that you are looking for but assume your animation on scroll isn't working as expected.
There is a tip on throttling scroll here that is incorrect. Let's say you throttle to every 30 milliseconds. If page stops scrolling 25 milliseconds after last animation then you're stuck with a scroll position 25 milliseconds before it stopped scrolling.
Maybe a better way to do it is this (can test in the console on this page):
var ol = document.querySelectorAll("ol")[2];
window.onscroll = ((lastExecuted)=>{
const expensiveHandler = e => {
lastExecuted=Date.now();
//do some animation maybe with requestAnimationFrame
// it may prevent overloading but could make animation
// glitchy if system is busy
console.log("1:",ol.getBoundingClientRect().top);
};
var timerID
return e=>{
if(Date.now()-lastExecuted>19){
//only animate once every 20 milliseconds
clearTimeout(timerID);
expensiveHandler(e);
}else{
//make sure the last scroll event does the right animation
// delay of 20 milliseconds
console.log("nope")
clearTimeout(timerID);//only the last is needed
timerID=setTimeout(e=>expensiveHandler(e),20);
}
}
})(Date.now())
So I have this function which scrolls down to the bottom of the page, and to the bottom of the scrollable div #log:
function gotoConsole() {
var console = document.getElementById('log');
window.scrollTo(0,document.body.scrollHeight);
window.setInterval(function() {
console.scrollTop = console.scrollHeight;
}, 250);
}
It does the job, it scrolls down to the page and scrolls to the bottom of the div. But the problem is; The div keeps on going down, I cannot scroll up.
The gotoConsole() function is called only once after the user clicks on a button.
What is the problem with this function? I cannot use jQuery for this.
I think that you may be misunderstanding setInterval. setInterval() will repeat infinitely unless you specifically clear it using clearInterval.
I believe what you're after is setTimeout - it functions very similarly to setInterval, though rather than repeating, it only runs once.
function gotoConsole() {
var myConsole = document.getElementById('log');
window.scrollTo(0,document.body.scrollHeight);
window.setTimeout(function() {
myConsole.scrollTop = myConsole.scrollHeight;
}, 250);
}
Side note:
Setting a variable to console is a major red flag.
When writing/debugging JavaScript, your best friend is very often going to be
console.log(). When you set a variable to the same name, you lose the ability to reference console within that scope without doing window.console.log() which is a cumbersome annoyance.
I am building an app in Ionic, and there are certain functions that load new sets of data into an existing view.
When I do this, sometimes if I have scrolled down, and the new data takes less space than the previous one, I am left with a blank screen until I scroll back up to where the new data is.
To prevent this, I am running an $ionicScrollDelegate.resize(); which works, but it doesn't refresh. If I swipe (to reload data) twice, it resizes the view and bumps the scroll up if necessary, however if I do it just once, the scroll resizes, however does not bring the user up automatically. They have to start scrolling first, then it snaps them back to a scroll area that actually has data present.
I managed to solve this by using a watch:
$scope.$watch(function(scope) { return scope.projects },
function() {
$ionicScrollDelegate.$getByHandle('taskScroll').resize();
}
);
But I do not want to use a $watch for performance reasons. I've tried using various methods to get this resize to work from the event that calls the data to be reloaded, including $apply, $evalAsync, $timeout...
None of them worked, except $timeout, but then only when the interval was 500ms. This tells me it is an issue with the speed at which the data is loading and that is why $watch worked cause it keeps looking.
Is there anything else I can do to make the resize work immediately? This is the code for the event handler function:
$scope.onSwipeRight = function () {
var operatingDate = appContextService.getOperatingDate()
.subtract(1,'days')
.startOf('day');
var pastDate = moment().subtract(1,'years')
.startOf('year')
.startOf('isoWeek');
if (isSwipeEnabled && operatingDate.isAfter(pastDate)) {
slideInCacheValidation(-1);
}
// Just one attempt at fixing this below, I've tried so many things that do not work...
$scope.$eval( function() {
$ionicScrollDelegate.$getByHandle('taskScroll').resize();
});
};
i have download this good plugin
http://andersonferminiano.com/jqueryscrollpagination/
and i use this code for do a call to my db and show all the result. The my problem is that i can't stop the showing results when are finish in the database, i wouold like stop the pagination and no repeat the same result. how can i do it? thank you so much
$(function(){
$('#content').scrollPagination({
'contentPage': 'democontent.html', // the page where you are searching for results
'contentData': {}, // you can pass the children().size() to know where is the pagination
'scrollTarget': $(window), // who gonna scroll? in this example, the full window
'heightOffset': 10, // how many pixels before reaching end of the page would loading start? positives numbers only please
'beforeLoad': function(){ // before load, some function, maybe display a preloader div
$('.loading').fadeIn();
},
'afterLoad': function(elementsLoaded){ // after loading, some function to animate results and hide a preloader div
$('.loading').fadeOut();
var i = 0;
$(elementsLoaded).fadeInWithDelay();
if ($('#content').children().size() > 100){ // if more than 100 results loaded stop pagination (only for test)
$('#content').stopScrollPagination();
}
}
});
// code for fade in element by element with delay
$.fn.fadeInWithDelay = function(){
var delay = 0;
return this.each(function(){
$(this).delay(delay).animate({opacity:1}, 200);
delay += 100;
});
};
});
That plugin actually isn't very good. I'm looking at the plugin's code, and sure enough, it doesn't provide a way to detect when you're at the end of the content.
If you go to the plugin page and scroll down, it appears to be working quite nicely. However, when you look at the file democontent.html (he's hidden the text, you have to view the source) where the data is being retrieved from, you'll see it's only 17 items. But, it keeps loading bogus data as you scroll down.
Not only does the plugin not detect the end of the data, but it also doesn't provide a way of stopping at all. If you'll notice, Anderson told the plugin to stop after 100 items are loaded, but he did this only in his example instead of writing this feature into the plugin.
So, that's why your content isn't stopping. You could try modifying his plugin yourself, but if you'd rather just change plugins, I'd recommend Infinite Scroll, by Paul Irish.
You can use mkscroll plugin with is provide you more functionality link for mk scroll is below.
https://github.com/maulikkanani/Scroll-Pagination
jQuery(window).mkscroll({
limit:10,
total:100,
});
there are many other option in that.
If any one phasing the problem here is the solution: the jscroll will stop the loading the content once the 'next page' link is not available.. so please check when you want to stop loading the content then 'next page' link is not getting loaded in the last content which is appended.