Remove and Add scroll event handler using jQuery .off or .unbind - javascript

I am writing my own image Lazy Loading function that when a div is scrolled to its bottom we load some new images, the height of the container div (#ScrollDiv in this case) is increased and when we scroll to the bottom again we make the same call. This is fine although I pass a 'pagination ID' with each request for more images (this is called appName.featureName.PaginationConstant and in a parent scope) and I want to remove or freeze the scroll event so we don't make other requests or increment the pagination ID. For example:
appName.featureName.lazyLoader = function() {
var currentScroll = $(this).scrollTop(),
divHeight = $(this)[0].scrollHeight,
actualHeight = $(this).height() + parseInt($(this).css('padding-bottom'))
// have we hit the bottom of the Scroll Div?
if((divHeight - actualHeight) <= currentScroll ) {
// yes we have, remove the scroll, see I name this function below
$('#ScrollDiv').off('scroll', appName.featureName.lazyLoader);
// Now get more photos, in the function below I shall re-bind the scroll functionality
appName.featureName.getMorePhotos(++appName.featureName.PaginationConstant);
}
};
// this is the lazyload funtion
appName.featureName.lazyLoad = function () {
$('#ScrollDiv').on('scroll', appName.featureName.lazyLoader);
};
Everything works great apart from the unbinding! I am still able to fire the scroll event handler despite the fact I have tried to remove it once my condition is met with $('#ScrollDiv').off('scroll', appName.featureName.lazyLoader);
What am I doing wrong?

Have you ever tried like this?
$('#ScrollDiv').on('scroll','#ScrollDiv', appName.featureName.lazyLoader);
and
$('#ScrollDiv').off('scroll','#ScrollDiv', appName.featureName.lazyLoader);
or you can use the method bind too
$('#ScrollDiv').bind('scroll', appName.featureName.lazyLoader);
and
$('#ScrollDiv').unbind('scroll', appName.featureName.lazyLoader);

jQuery's .off() function doesn't work that way. If you wanna add and remove only your own scroll handler and leave other 3rd party scroll handlers alone, you want to use
$("#scrollDiv").on("scroll.appName", appName.featureName.lazyLoader);
and to remove all of your own handlers:
$("#scrollDiv").off(".appName");
or, to only remove your own scroll handler, but leave a click handler alone:
$("#scrollDiv").off("scroll.appName");
See the documentation at http://api.jquery.com/off/ for more information.

Related

fullpage.js: disable page scroll when scrolled with the mouse pointer inside a container

What's happening: Scrolling works no matter which position i have the mouse while i scroll.
What i want to achieve: When the user scrolls with the mouse pointer positioned inside a particular container, I would like to disable the plugin from changing pages. When the user scrolls with the mouse pointer outside that same container, the normal functionality of the plugin should be restored; i.e. the pages should be scrollable again.
What have i tried: I listened for the scroll event on the document and found out whether the mouse is inside the container while executing the scroll and store the possibilities as a boolean.
$(document).bind("mousewheel", function(event) {
// preventScroll = true;
console.log(event);
if($(event.target).closest(".no-scroll").length) {
preventScroll = true;
}
else {
preventScroll = false;
}
});
Then onLeave i try to find out the value of preventScroll and try to stop event propagation (since in want to stop an actual event) by returning false
setTimeout(function() {
console.log(preventScroll);
if(preventScroll) {
console.log("no-scroll")
return false;
}
}, 10);
I an using setTimeout to capture the desired value of preventScroll although I guess the plugin executes a scroll within that 10 ms and that's why return false doesn't seem to have an effect. I can't seem to figure out how else to proceed to achieve the desired functionality.
Codepen: https://codepen.io/binarytrance/pen/YxBqPj
In this implementation, the container i want to disable scroll is in the second page/section. Please be aware of the values spit out in the console.
Use the fullpage.js option normalScrollElements. Check the fullpage.js docs for more info:
normalScrollElements: (default null) If you want to avoid the auto scroll when scrolling over some elements, this is the option you need to use. (useful for maps, scrolling divs etc.) It requires a string with the jQuery selectors for those elements. (For example: normalScrollElements: '#element1, .element2'). This option should not be applied to any section/slide element itself.

jQuery scroll function fire once when element becomes visible

Hi guys I am using the scroll function on this script but it fires each time a user scrolls. I want it to only fire once when the user scrolls down to #ror. I tried using the fired variable to check if it has already been fired but that didn't seem to work. I know some people have answered this before but this is where i got the fired solution from and cant get it to work only once. Anyone think they can help please?
$( window ).scroll(function() {
var fired = 0;
console.log(fired);
if(fired == 0){
$('#ror').html('');
$('#ror').goalProgress({
goalAmount: 100,
currentAmount: 75,
textBefore: 'progress bar',
textAfter: '',
offset: 10,
});
fired=1;
}
});
You need to move the fired variable outside the scroll function.
As you are doing it now you are reinitializing the fired variable and setting it to 0 each time the scroll event gets fired.
var fired = 0;
$(window).scroll(function() {
console.log(fired);
if(fired == 0){
$('#ror').html('');
$('#ror').goalProgress({
goalAmount: 100,
currentAmount: 75,
textBefore: 'progress bar',
textAfter: '',
offset: 10,
});
fired=1;
}
});
To detect when a given #target scrolls into view, you can look at it's top position, and check if that position is already inside the viewport.
$('#target').offset().top - $(window).outerHeight() > $(window).scrollTop();
That left part of the equation is constant (as long as you don't move anything around, or change the size of the viewport). Therefore it may be wise to move that outside your event handler function. You need to keep in mind that the scroll event is rather expensive, since it fires constantly when you are scrolling, and the browser is already quite busy with the rendering of the viewport.
When the work is done, you can remove the event handler.
$(window).off(event);
So your final code would look something like this:
var triggerAtY = $('#target').offset().top - $(window).outerHeight();
$(window).scroll(function(event) {
// #target not yet in view
if (triggerAtY > $(window).scrollTop()) {
return;
}
// run your task
// remove this event handler
$(this).off(event);
});
Have a look at the demo: https://jsfiddle.net/6whnfa02/1/
Docs:
http://api.jquery.com/offset/
http://api.jquery.com/outerHeight/
http://api.jquery.com/scrollTop/
http://api.jquery.com/off/
$(window).scroll(function(event) {
var eT = $('#ror').offset().top,
wH = $(this).height(),
wSt = $(this).scrollTop();
if(wSt > (eT-wH)) {
alert('you have scrolled to the ror!');
//detach scroll event handler, as we dont want it to fire again
$(this).off(event);
}
}
The above code checks if user has scrolled down to an element. If yes, alert something and detach the scroll event handler for window. You can refer jquery documentation to see the meaning of offset, height and scrollTop.
Now, as #Pevera pointer out, it is costly to attach event handler to window scroll, you should be aware of that. If you have some heavy code execution inside scroll callback, it will hamper in scrolling the page. So, if you have to attach handler to window scroll, run the scroll callback code within a timeout callback. It ensures to run the scroll callback code after certain delay which helps to scroll the page better. Rewriting the above code with timeout will look like this:
var timeout = null;
$(window).scroll(function (event) {
if (!timeout) {
// set a timeout to run after 250ms
timeout = setTimeout(function () {
clearTimeout(timeout);
timeout = null;
var eT = $('#ror').offset().top,
wH = $(this).height(),
wSt = $(this).scrollTop();
if (wSt > (eT-wH)){
alert('you have scrolled to the ror!');
//detach scroll event handler, as we dont want it to fire again
$(this).off(event);
}
}, 250);
}
});
Everytime user scrolls the page, a timeout is set to run after(atleast) 250ms. In the timeout callback, we remove this timeout handler and check if user has scrolled to the element. If yes, we alert something and detach the scroll handler for window so that it doesn't run again.
Please refer to this FIDDLE for better understanding.
More info on this stackoverflow post and John Resig's blog post.

scrollTop returns 0 for all document elements in javascript but scroll event fires on body tag

I made an event handler for the scroll event on the body tag which fires correctly. However when I try to find the position of the scollbar using scrollTop(), I was unable to do so. To figure out which element was being scrolled I logged the scrollTop() of all the DOM elements but surprisingly all were 0.
$('body').scroll(function () {
var all = document.getElementsByTagName("*");
for (var i=0, max=all.length; i < max; i++) {
console.log('scrolltop', all[i].scrollTop);
}
});
All I want to know is the position of the scrollbar and whether the scrollbar has reached the end or not. I have tried $(document).scroll() and $(window).scroll, but none of them fires. The event only works on the body tag.
Using the window object is usually the most reliable for tracking scrolling.
ScrollTop also only really tracks how much the window has been scrolled and although commonly confused for doing so, it does not track how far an element is from the top of the page. For that you need to use offset.
As such I have simply changed your code to run on the window scroll and also changed your logic to use jQuerys each function which will make things simpler.:
JS:
$(window).scroll(function () {
$('*').each(function (){
console.log(
'Element Text:', $(this).text(),
' | From Top', $(this).offset().top
);
})
});
With the above JS you will see in your console the following output:
Element Text: hello87 | From Top 1556
JsFiddle:
https://jsfiddle.net/wigster/t1e3dee8/1/

How can I prevent a custom event from being triggered repeatedly – or can I "reset" the jQuery .one() function?

I have some code, that checks for the visibility of an element on the screen. As soon as it comes in sight by scrolling the page a custom event is triggered. This custom event starts an animation. To prevent this animation to be started over and over the function that starts it is only started once. For that I used the jQuery function .one().
The function to check if element is visible:
checkScrollPos = function() {
if (objTopPos - scrollPos <= windowHeight / 2) {
$(document).trigger('objVisible');
}
}
The function to listen for the event:
evtListener = function() {
//startAnimation() should only be started once
$(document).one(
{
'objVisible': function(event) {
startAnimation();
}
}
);
}
Here it all happens:
$(document).ready(function() {
evtListener();
$(window).scroll(function () {
scrollPos = $(document).scrollTop();
checkScrollPos();
}
}
Now this all works fine but I extended the checkScrollPos() function to also check if the element gets out of sight again, to then stop the animation. That works fine to. Problem is, as the events trigger, the event-bound functions only are executed one time. So when you scroll teh element in sight, then out of sight and then in sight again the animation will not be executed again (what is the correct behaviour of course). Now I would like to have it that the events are triggered exactly one time but EVERYTIME the element gets in or out of sight and not just one time at all. So basicly I need some kind of reset for the
$(document).one()
function – so that everytime the element gets out of sight, I can use the .one() function again. Is there any way to do that?
You have to bind the objVisible event every time the element disappears.
Just call evtListener() after the element is out of sight, so that the objVisible event is bound again.
Your code would be something like this:
checkScrollPos = function() {
if (objTopPos - scrollPos <= windowHeight / 2) {
$(document).trigger('objVisible');
}
if (/* your condition to check if element is out of sight */) {
evtListener();
}
}

need an event triggered if the page has scrolled 200px down (jQuery)

I want to show and hide a piece of code if i scroll and the page is for example half way, i have tried to use window scroll but this doesnt works(no errors, clean code, different browsers, different jQuery versions), but this doesn't trigger anything, so i am looking for a better way to show and hide a div if i scrolldown.
used this to trigger an event(not working)
$(window).scroll(function(){
alert('works')
});
Try using the window.onload function (that's how they use it in jQuery examples):
window.onload = (function(){
$(window).scroll(function () {
if( $(window).scrollTop() > 200 ) {
// Display something
}
})
})

Categories

Resources