iScroll library - end of page reached - callback or binding? - javascript

I'm trying to hook function callback when iScroll container reaches end of page, at the bottom end (Y-axis). So that I can load more content on demand - instead of all 300+ contents.
Has anybody worked on it? Any hints?
Here is the library I was referring to: http://cubiq.org/iscroll-4

As drmatt metioned, you should look into Pull to refresh demo
http://cubiq.org/dropbox/iscroll4/examples/pull-to-refresh/
You need to build you own logic which won't require user to pull to add more items.
Something like following (pseudo code - not tested code):
var isAlreadyLoading = 0;
var iscroller = new iScroll(
'your-element-id',
{
hScroll: false,
bounce: false, // do not bounce
onScrollMove: function () {
// CHECK if we've 350px gap before reaching end of the page
if ( (this.y < (this.maxScrollY + 350)) && (isAlreadyLoading == 0) ){
// start loading next page content here
// update this flag inside load more and set to 0 when complete
isAlreadyLoading = 1;
}
},
onScrollEnd: function () {
// check if we went down, and then load content
if ( isAlreadyLoading == 0 ) {
// Load more content
// update this flag inside load more and set to 0 when complete
isAlreadyLoading = 1;
} else {
// DO NOTHING
}
}
} // end of Scoller config object
); // end iScroll instance

Related

How to execute javascript code after full load of PHP table?

My page has a somewhat large table (~ 300 lines), loaded from a database in PHP. When the user roll the table with any scrollbar (horizontal/vertical), I save both positions to go exactly there after page reload.
Problem is: sometimes the vertical position won't be fully restored, as if the code tried to execute before the PHP table is fully drawn.
I've tried to attach the code in different ways:
<body onload='load()'>
window.onload = load;
window.addEventListener('load',load);
document.addEventListener('DOMContentLoaded',load);
document.addEventListener('readystatechange', event => {
if (event.target.readyState === 'complete') {
load();
}
});
But none of the above works all the time. After every reload, the page sometimes scroll back to the right position, other times it scrolls upwards, until a point (~ 1000 px, which I can see in the console) where it's able to keep position indefinitely.
The code to save the scrollbar position is:
<div id='tab' onscroll='moved(this)'>
function moved(w) {
localStorage.setItem('db.scrLeft',w.scrollLeft);
localStorage.setItem('db.scrTop',w.scrollTop);
console.log(w.scrollTop);
}
And to retrieve the scrollbar position, inside load() is:
if (document.getElementById('tab')) {
var sl = parseInt(localStorage.getItem('db.scrLeft'),10);
var st = parseInt(localStorage.getItem('db.scrTop'),10);
if (sl && st) {
document.getElementById('tab').scrollLeft = sl;
document.getElementById('tab').scrollTop = st;
console.log(st);
}
}
Why is none of the above options respecting the proper table load, as they should? And how do I achieve it?
Solved it. The scrollbar was rolling during load, causing the moved function to be called. I added a condition (loaded) to allow its execution only after load.
var loaded = false;
function moved(w) {
if (loaded) {
localStorage.setItem('db.scrLeft',w.scrollLeft);
localStorage.setItem('db.scrTop',w.scrollTop);
}
}
function load() {
if (document.getElementById('tab')) {
var sl = parseInt(localStorage.getItem('db.scrLeft'),10);
var st = parseInt(localStorage.getItem('db.scrTop'),10);
if (sl && st) {
document.getElementById('tab').scrollLeft = sl;
document.getElementById('tab').scrollTop = st;
loaded = true;
}
}
}

Scroll bottom in JavaScript

I have a working bottom function in JavaScript to detect if the user scrolls at the bottom. However, a problem comes when the user has a strange resolution (like windows scale) or when you zoom. The function is not working anymore and can't detect the bottom.
Here is what I did :
const bottom = e.target.scrollHeight - e.target.scrollTop === e.target.clientHeight;
if (bottom) {
this.props.getNewValues();
}
Is there a way to avoid that? Even when you don't zoom, this is not working for people displaying the site on a TV or something like this (like a friend of mine did)
Thanks you
EDIT : I'm applying this on a precise element and I repeat that my solution is working except by unzooming. Unzooming provides float values that made the response not really accurate (it goes from 1 to 50px of difference based on the zoom made)
I use this function (can't take credit as someone else wrote it - sorry for no credit - it was ages ago). Maybe you can adapt this to your use case:
(function($) {
//CHECK SCROLLED INTO VIEW UTIL
function Utils() {
}
Utils.prototype = {
constructor: Utils,
isElementInView: function (element, fullyInView) {
var pageTop = $(window).scrollTop();
var pageBottom = pageTop + $(window).height();
var elementTop = $(element).offset().top;
var elementBottom = elementTop + $(element).height();
if (fullyInView === true) {
return ((pageTop < elementTop) && (pageBottom > elementBottom));
} else {
return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
}
}
};
var Utils = new Utils();
//END CHECK SCROLLED INTO VIEW UTIL
//USING THE ELEMENT IN VIEW UTIL
//this function tells what to do do when the element is or isnt in view.
//var inView = Utils.isElementInView(el, false); Where FALSE means the element doesnt need to be completely in view / TRUE would mean the element needs to be completely in view
function IsEInView(el) {
var inView = Utils.isElementInView(el, false);
if(inView) {
//console.log('in view');
} else {
//console.log('not in view');
}
};
//Check to make sure the element you want to be sure is visible is present on the page
var variableOfYourElement = $('#variableOfYourElement');
//if it is on this page run the function that checks to see if it is partially or fully in view
if( variableOfYourElement.length ) {
//run function on page load
IsEInView(variableOfYourElement);
//run function if the element scrolls into view
$(window).scroll(function(){
IsEInView(variableOfYourElement);
});
}
//END USING THE ELEMENT IN VIEW UTIL
})(jQuery);

JavaScript/jQuery image slider issue

Fiddle: https://jsfiddle.net/8na2n5L2/
I'm trying to create an image slider, but for some reason just can't wrap my head around why this isn't working. I'm basically trying to create a slider where images come in from the right (off screen), and the center image gets pushed to the left (off screen). Then, when it comes time for that left image to go to the center again, it quickly goes back to the right again before going to the center.
jQuery(document).ready (function () {
var images = [];
//store the images in an array
jQuery('.main-image-slider').each( function () {
images.push(jQuery(this));
});
var i = 0;
var max = images.length - 1;
setInterval( function () {
if ( i > max) {
i = 0;
}
images[i].removeClass('main-image-slider-left').addClass('main-image-slider-right').delay(100).queue(function () {
images[i].removeClass('main-image-slider-right').addClass('main-image-slider-center').dequeue();
i++;
});
if (images[i - 1]) {
images[i - 1].removeClass('main-image-slider-center').addClass('main-image-slider-left');
}
}, 3000);
});
I get this console error "Uncaught TypeError: Cannot read property
'removeClass' of undefined".
This error is because the code will run i++ first, then run images[i].removeClass('main-image-slider-right')....
images[i].removeClass('main-image-slider-left').addClass('main-image-slider-right').delay(100).queue(function() {
// the 'i' is already added 1, so it may equal images[max], so you got that error
images[i].removeClass('main-image-slider-right').addClass('main-image-slider-center').dequeue();
});
You can move i++ into queue:
images[i].removeClass('main-image-slider-left').addClass('main-image-slider-right').delay(100).queue(function() {
images[i].removeClass('main-image-slider-right').addClass('main-image-slider-center').dequeue();
// after all the animation is done, at the end of queue update 'i'.
i++;
});
You can try this.
Note: don't forget to remove the i++ at the end of code.
Update
Update the jsfiddle code
At the edge of slides it will not update the class with if (images[i - 1]), wee need always update the class of previous slide. So I changed the code to
images[i == 0 ? images.length - 1 : i - 1].removeClass('main-image-slider-center').addClass('main-image-slider-left');

Javascript vertical scrolling function

I am trying to detect a scroll on my page using JavaScript. So that I can change classes and attributes of some elements when user has scrolled certain amount of page. This is my JS function:
function detectScroll() {
var header = document.querySelector(".headerOrig"),
header_height = getComputedStyle(header).height.split('px')[0],
fix_class = "changeColor";
if( window.pageYOffset > header_height ) {
header.classList.add(fix_class);
}
if( window.pageYOffset < header_height ) {
header.classList.remove(fix_class);
}
var change = window.setInterval(detectScroll, 5000);
}
and I am calling it when the page is loaded:
<body onload="detectScroll();">
However, I have this problem - I need to set up a really small interval so that the function gets called and the class is changed immediately. BUT then the page freezes and everything except the JS function works very slowly.
Is there any better way of achieving this in JavaScript?
Thanks for any advice/suggestion.
You are going to want to change a couple things. First, we can use onscroll instead of an interval. But you are also going to want to cache as much as possible to reduce the amount of calculations on your scroll. Even further, you should use requestAnimationFrame (or simply "debounce" in general for older browsers -- see the link). This ensures your work only happens when the browser is planning on repainting. For instance, while the user scrolls the actual scroll event may fire dozens of times but the page only repaints once. You only care about that single repaint and if we can avoid doing work for the other X times it will be all the more smoother:
// Get our header and its height and store them once
// (This assumes height is not changing with the class change).
var header = document.querySelector(".headerOrig");
var header_height = getComputedStyle(header).height.split('px')[0];
var fix_class = "changeColor";
// This is a simple boolean we will use to determine if we are
// waiting to check or not (in between animation frames).
var waitingtoCheck = false;
function checkHeaderHeight() {
if (window.pageYOffset > header_height) {
header.classList.add(fix_class);
}
if (window.pageYOffset < header_height) {
header.classList.remove(fix_class);
}
// Set waitingtoCheck to false so we will request again
// on the next scroll event.
waitingtoCheck = false;
}
function onWindowScroll() {
// If we aren't currently waiting to check on the next
// animation frame, then let's request it.
if (waitingtoCheck === false) {
waitingtoCheck = true;
window.requestAnimationFrame(checkHeaderHeight);
}
}
// Add the window scroll listener
window.addEventListener("scroll", onWindowScroll);
use onscroll instead of onload so you don't need to call the function with an interval.
Your dedectScroll function will be triggered automatically when any scroll appers if you use onscroll
<body onscroll="detectScroll();">
Your function is adding an interval recursively, you should add an event listener to the scroll event this way :
function detectScroll() {
var header = document.querySelector(".headerOrig"),
header_height = getComputedStyle(header).height.split('px')[0],
fix_class = "changeColor";
if( window.pageYOffset > header_height ) {
header.classList.add(fix_class);
}
if( window.pageYOffset < header_height ) {
header.classList.remove(fix_class);
}
}
window.addEventListener("scroll",detectScroll);

jQuery wait for an action to complete on different functions

I have created a newsfeed. The feed switches every 2 seconds. You can also manually switch left/right, or click the panel from the squares at the bottom. The switching between slides is down using jQuery UI Slide.
Right now, if you are in the middle of a slide, and you click left/right/squares, then another slide occurs on top of the existing, still going slide and the whole system is messed up.
How can I prevent other actions occurring if a slide/switch is already in progress?
This is my code:
$(document).ready(function(){
newsfeedTimer = setInterval(newsfeed, displayDuration);
// Manual change of feed (LEFT)
$('#newsfeeds_wrapper > .left').click(function(event){
event.stopPropagation();
feedLeft();
clearInterval(newsfeedTimer);
newsfeedTimer = setInterval(newsfeed, displayDuration);
});
// Very similar code for feed right
// Ignore the other method of switching (if it works for above, I can implement it for this one)
});
function newsfeed() {
feedRight();
}
// Feed to the Right
// jump is used to jump multiple newsfeed instead of one at a time
function feedRight(jump)
{
jump = typeof jump !== 'undefined' ? jump : 1;
var current = $('.newsfeed:first');
var next = $('.newsfeed:nth(' + jump + ')');
current.hide('slide',{duration: transitionDuration}, function(){
// Append as many needed
for( var i = 0; i < jump; i++ ) {
$('.newsfeed:first').appendTo('#newsfeeds');
}
next.show('slide',{direction : 'right' , duration: transitionDuration});
}
I don't want to stop() an animation! I want to disable changing the slides IF there is animation happening!!
without seeing the full breadth of the code, I am shooting myself in the foot here. But here is a direction I would take it. You could also have two functions, one to bind, another to unbind. When animation is initiated, you unbind the left/right controls. When stopped, you bind. Or, set a global variable... ala.
var config = {'inProgress': false};
$('#newsfeeds_wrapper > .left').click(function(event){
if(!config.inProgress){
event.stopPropagation();
feedLeft();
clearInterval(newsfeedTimer);
newsfeedTimer = setInterval(newsfeed, displayDuration);
}
});
in your animation function. Seems like when you cut/paste, some of the code is lost, so lets just assume some animation.
when you enter your animation functions, set config.inProgress = true;
function feedRight(jump)
{
config.inProgress = true;
// removed your code, but just using for simplicity sake
// added a callback
next.show('slide',{direction : 'right' , duration: transitionDuration},
function() {
// Animation complete. Set inProgress to false
config.inProgress = false;
});
)
}

Categories

Resources