I have an empty HTML page with just a div and a button to load data.
<body>
<div id="main_div"></div>
<button class="load_more" onclick="myFunction()">Load More..</button>
</body>
myFunction is a function which creates and populate the div main_div.
I want to create an infinite scroll view out of it.
I have added scroll listener which call myFunction and loads the data once only 200px is left. (I got this code from a blog online)
$(window).on('scroll', function() {
console.log('Scroll detected')
var scrollHeight = $(document).height();
var scrollPos = Math.floor($(window).height() + $(window).scrollTop());
var isBottom = scrollHeight - 200 < scrollPos;
if (isBottom && currentscrollHeight < scrollHeight) {
$('.load_more').click();
currentscrollHeight = scrollHeight;
}
});
The infinite scroll works fine when I manually tap the load button a few times and the page is loaded with elements. After that when I scroll, it loads new data.
But what I want is to fill the initial space from the same API.
I thought of calling the same function multiple time, but I am not sure how many times should I call, as the page can be opened from a mobile or any browser and I would not know the height of that.
Also, I want to avoid JQuery or other frameworks to keep it minimal. I know the code is already using JQuery, but I plan to remove it.
you can call a function which will check your div height and compare it with windowHeight. Till div height less than windowHeight you should call that function
Like
document.addEventListener("DOMContentLoaded", function(e) {
function loadData(callBackFunction) {
// your function body
// in your ajax success request add following line
if (callBackFunction) {
callBackFunction();
}
}
function loadInitialData() {
if (document.getElementById('main_div').getBoundingClientRect().height < window.innerHeight) {
loadData(loadInitialData);
}
}
(function() {
loadInitialData();
})();
// Also Your click event won't work here(inside the listener function).
// So it isn't visible outside of this function's scope.
// If you want to call the method directly 'from the button', then you have to attach it to `window`
window.loadData = loadData;
})
Related
I added a class to <header> via JS when the page is scrolled like this:
$(window).scroll(function(){
var top = $(window).scrollTop();
if(top>=1){
$("header").addClass('bg-header');
}
else
if($("header").hasClass('bg-header')){
$("header").removeClass('bg-header');
}
});
The issue is that let's say for example I reload from the footer section of the page (or any other section that is lower than the very top of the page), then the header looses the class, and only gets it back after I scroll down. How would I make it so that it wouldn't loose the added class after reload ?
There are two approaches: you can manually fire the scroll event on page load/DOM ready, or simply move all the logic into a function which is called by the scroll event and during page load/DOM ready.
Solution 1: Call custom function during scroll + page
$(function() {
// Define custom function that contains all the logic
var customScrollCallback = function() {
var top = $(window).scrollTop();
if (top >= 1) {
$("header").addClass('bg-header');
} else if ($("header").hasClass('bg-header')) {
$
};
};
$(window).scroll(function() {
// Call custom function during scroll
customScrollCallback();
});
// Call custom function at runtime :) (this is the trick!)
customScrollCallback();
});
Solution 2: Trigger scroll event manually (not ideal)
The reason why this solution is not ideal is because there might be other plugins/scripts on the page that are listening to the scroll event. By manually triggering it, you are subverting the default behaviour of the event (because the event is fired without any actual scrolling).
$(function() {
$(window)
.scroll(function() {
var top = $(window).scrollTop();
if (top >= 1) {
$("header").addClass('bg-header');
} else if ($("header").hasClass('bg-header')) {
$("header").removeClass('bg-header');
}
})
.trigger('scroll');
});
I have this 2 pieces of code
function fixFooter() {
var wrapper = $('#disqus_wrapper').height();
if ( wrapper > 200 ) {
$(window).trigger('resize');
}
};
var element = $('#disqus_wrapper');
new ResizeSensor(element, function() {
fixFooter();
});
The expected effect is that the window will resize every time the div#disqus_wrapper changes height. (to fix comments and footer overlapping)
Well the code works, but only once after the page loads. I need it to resize each time the div changes in height. I tried switching the trigger('resize') function with an alert and everything works perfectly. Any idea why the trigger('resize') only works once and how can I fix it?
Update ;
The html is just this because I am loading the Disqus comment system
<div id="disqus_wrapper"><div id="disqus_thread"></div></div>
For detecting the div height change I am using this library
https://github.com/marcj/css-element-queries (the ResizeSensor.js)
You need to call your function fixFooter() in window resize event.
$( window ).resize(function() {
fixFooter();
});
I have an endless scrolling made by ajax and jQuery. It's using the items paginated in Controller (Laravel5), getting it with ajax.
Everything works fine, however I have a problem. When I hit the bottom of the page, it makes an ajax call twice. I suspect it's because of the setInterval because when I change the time, it affects exactly that part.
// Creates the pagination pages [<[1]2]3]>]
{!! $boxes->render() !!}
// Html
<input type="hidden" id="page" value="1" />
<input type="hidden" id="max_page" value="{{{ $boxes-id }}}" />
<div id="end_of_page" class="center">
<hr/>
<span>End of the feed.</span>
<script>
$(document).ready(function() {
var didScroll = false;
$(window).scroll(function() { //watches scroll of the window
didScroll = true;
});
//Sets an interval so your window.scroll event doesn't fire constantly. This waits for the user to stop scrolling for not even a second and then fires the pageCountUpdate function (and then the getPost function)
setInterval(function() {
if (didScroll){
didScroll = false;
if(($(document).height()-$(window).height())-$(window).scrollTop() < 10){
pageCountUpdate();
}
}
}, 250);
When I change 250 to 5000 for example, it gives a time in between, but this is not what I want to make. I want to make the call only one time once I hit the bottom, maybe disable it with a boolean variable, and then reactivate it after new elements load (on ajax success state), but I couldn't figure it out where to put the blocking variable.
//Continuing
function pageCountUpdate(){
var page = parseInt($('#page').val());
var max_page = parseInt($('#max_page').val());
if(page < max_page){
$('#page').val(page+1);
getPosts();
$('#end_of_page').hide();
} else {
$('#end_of_page').fadeIn();
}
}
function getPosts(){
var data = { "page": $('#page').val() }
$.ajax({
type: "POST",
//Classic ajax call
beforeSend: function(){
..}
complete: function(){
..}
success: function(){
..}
});
}
}
});
Update: Regarding to John Resig's example mentioned in comments, I need to use var outerPane = $details.find(".details-pane-outer"),
didScroll = false;. I think not having this part creates my problem, but I couldn't figure out where to choose with find() method.
apart from your weird setinterval structure (just move the code into the scroll event, without an interval).
It seems that the scroll event is called multiple times inside the last 10 pixels of the bottom of the page. So while scrolling to the bottom, at 9 px away form the bottom, the event is fired which loads more posts. But even before the new posts are loaded, in the meanwhile you scroll a little further which again fires the scroll event. This makes your posts load twice or even more than twice.
To solve this you can add a simple boolean switch that makes sure that the posts don't get loaded again when they're already being loaded. Something like:
var loading=false;
function onReachScrollLimit(){
if(loading){return;}
loading=true;
load_new_posts();
}
function load_new_posts(){
//insert the posts
loading=false;
}
So I'm doing lazy loading on a ListView on one jQuery page. When you click the ListItem it takes you to a details page. The problem is, that since I've binded a scrollstop event to the window, that the lazy load still tries to fire on the details page.
$("#index").on("pageshow", function () {
//get initial list view data
var inital = $('#filters').serialize(); //gets 'filter' params for data-access
RetrieveMeetings(inital); //Populate initial set
//lazy load
//Window Event From: http://stackoverflow.com/questions/9983835/detect-if-user-has-scrolled-to-the-bottom-of-a-div
$(window).bind('scrollstop', function () { //this also fires on details page!!!
var screenBottom = $(this).scrollTop() + parseInt($(window).height());
var $div = $('#meetings-list');
var divBottom = $div.offset().top + parseInt($div.height());
if (screenBottom > divBottom) {
var values = $('#filters').serialize();
LoadMoreMeetings(values);
}
});
//new dataset from filter forum
$("#submit").click(function (event) {
/* stop form from submitting normally */
event.preventDefault();
var values = $('#filters').serialize();
ResetMeetingList();
RetrieveMeetings();
});
});
I could fix this by removing the page from the DOM on the pagehide event but then I lose page state of a filter forums and such whenever the user returns to the ListView (also it increases pageload time).
//remove pages from DOM on hide
$(document).on("pagehide", function (e) {
$(e.target).remove();
});
Is there someway to attach the scrollstop event to the page instead of the window?
Another issue with this method is that if the Screen is big enough to load the page without a scroll bar then the lazy load obviously wont fire! Maybe there's a better overall solution for this problem?
I want to reload the page only once if a given div is positioned higher than position:absolute; top:15%.
I think this could be done with jQuery's .css method, something like:
if ('#mydive').css('top') > '15%' {
//reload the page
}
Could someone suggest a simple solution, preferably jQuery or pure JavaScript?
If what you meant is the top of the document, you can probably try:
var percent = .15; // 15%
if ($('#yourdiv').offset().top > ($(document).height() * percent)) {
window.location.reload();
}
// if by pixels
var pixels = 10; // 10px
if ($('#yourdiv').offset().top > pixels) {
window.location.reload();
}
You can check the current position of a div using the Computed Style
If you are have a like an animation or a drag and drop, you can use the onmousemove event to track the position of the div. but be careful the mousemove will be trigger for every pixel it moves and it my use lots of process time, so be wise on how you use it :)
Well, it is rather hard to say how you should determine the position of the div since you presented no code, but basically you should write a function that fetches the window height and the offset of the div relative to the top of the window to determine whether it is higher than 15%. You then need to call this function every time using the window.onscroll event listener. When the function returns true, trigger trigger window.location.reload(true) to reload the page. I imagine this could be done fairly easily in jQuery as well.
the above answers point you in the right way, but in order to "reload the page only once", you need an extra ingredient. you need a way to store a flag that points out whether the page has already been reloaded or not.
Say you follow tradyblix's code.
You should check for that flag before reloading your page :
if (hasReloaded() && $('#yourdiv').offset().top > ($(document).height() * percent)) {
reload();
}
where hasReloaded is a function that determins if the page has been reloaded, and it can be either a function that sends an ajax request to a server, that checks a cookie or even the localStorage object:
function hasReloaded(){
return !!localStorage['reloaded'];
}
In order to set that flag, your reload function needs to access the localStorage (or cookie or ajax server response) :
function reload(){
localStorage['reloaded'] = true;
window.location.reload();
}
This is just a sketch of how you should write this functionality.