unbind jQuery infinite scroll when used alongside pjax - javascript

I'm using a very simple jQuery infinite scroll to eliminate the need for numbered pagination but I'm coming across a small issue.
When I go to the page that uses the infinite scroll and it loads it, the infinite scroll will work as planned but when I then navigate away from that page using pjax it will still run on all other site pages as it's still a loaded function?
What can I do to basically tell the infinite scroll function to only run on the pages I want it to or somehow reset it when pjax changes the page?
Here's my code for the infinite scroll so far:
$(window).on("scroll", function() {
if($(window).scrollTop() == $(document).height() - $(window).height()){
// Do scroll pagination, load content into #load-here ..
}
}
This is how I want the scroll to function:
$("a:not(.no-dynamic)").pjax("#main");
$(document).on('pjax:end', function() {
if($("#load-here").length == 0) {
$(window).off("scroll");
}
else
$(window).on("scroll");
});

I had similar issue. Fixed it by unbinding the scroll handler if a particular div (hidden pagination div) doesn't exists any more.
$(window).scroll(function()
{
if($('#pagination').length == 0){
$(window).unbind('scroll',<<scroll handler function>>);
return;
}
......
}

Try this:
Instead of $(window).scroll(), do:
$(window).on('scroll', function() {
// stuff
});
I've never used pjax, but according to the docs, there's an end callback you can use:
$(document)
.on('pjax:end', function() {
$(window).off('scroll');
});
The idea is to unbind the "scroll" event from window every time a pjax request ends.

handle window.onbeforeunload to unbind infinite scroll

Related

JavaScript width checking to disable event

I have some code which adds a class at a certain page scroll point, which I need for a particular scenario however I do not need this on mobile.
$(window).scroll(function() {
if ($(".navbar").offset().top > 500) {
$(".navbar-fixed-top").addClass("top-nav-collapse");
} else {
$(".navbar-fixed-top").removeClass("top-nav-collapse");
}
});
Could I combine this with something like...
function checkWidth() {
if ($(window).width() < 514) {
$('#menu2').addClass('f-nav');
} else {
$('#menu2').removeClass('f-nav');
}
}
$(window).resize(checkWidth);
To say switch the classes but only if the width is above say 480px?
I appreciate this is probably newbie but I wondered if the window scroll function could just be part of the if condition?
Try out this fiddle:https://jsfiddle.net/cxn6t946/
You need to put if ($(window).width() > 514) inside the scroll function and it will work.
Edited my answer as the previous fiddle had a problem. It worked fine on sceen size >514 and added top-nav-collapse on an offset>500. However on returning to screen size <514 the top-nav-collaspe class remained there. So had to rewrite the fiddle by incorporating resize.
Check out the updated fiddle:https://jsfiddle.net/cxn6t946/1/
Hope this helps.
If you place the conditional check on the event listener as opposed to the action of the event listener, you can save yourself some resources on mobile while also accomplishing your task.
Try:
if ($(window).width() > 514) {
$(window).scroll(function() {
if ($(".navbar").offset().top > 500) {
$(".navbar-fixed-top").addClass("top-nav-collapse");
} else {
$(".navbar-fixed-top").removeClass("top-nav-collapse");
}
});
}
By doing the conditional check before applying the event listener, you're not adding an event listener on mobile devices and saving the resources it would be using. This also keeps you from having to add any conditional logic to your functionality since it won't be getting called without the scroll listener being applied on devices smaller than 514px.

.delay() a .css() action by multiplying an index number

I am trying to create a script that does the following:
Waits until a point on the page is reached by scrolling (.clients with an offset of 500px
Start fading in img's contained inside the .clients div once this event is triggered
Fade in with a slight delay between each item (so they fade in in sequence)
Due to other parts of my code the fade-in has to be with change of opacity:1 and cannot be .fadeIn()
I'm somewhere there but having a few issues. Here is my code:
var targetOffset = $(".clients").offset().top;
var $w = $(window).scroll(function(){
if ( $w.scrollTop() > targetOffset-500 ) {
$('.home .clients img').each(function(index){
console.log(index);
$(this).delay(500 * index).css('opacity','1');
});
}
});
First problem
The event does fire at the correct scroll-point in the page, but it continues to fire. I would like it to only fire once and then not register again. When 500 above .clients is reached, the event should fire, and never again.
Second problem
My .each() does not seem to work correctly. Everything fades in at once. My method for making a small .delay() between the fade-ins doesn't seem to be working. I tried multiplying the index by 500. So the first index is 0, so it fires immediately. The second index is 1 so it should fire after 500 milliseconds and so on. I'd like to work out why this method isn't working.
Any help appreciated. I'd appreciate trying to make the code above work rather than writing something entirely new, unless that's the only way. I'd appreciate explanation of what I was doing wrong so I can learn, instead of just pure-code answers.
JSFiddle
Sidney has attacked most of the problems except one. The scroll event fires multiple times, so it checks the conditional multiple times and then actually sets the animation multiple times. To keep this from happening, I typically like to add another boolean to check if the process has fired at all. I've simplified the code to make the changes more legible.
var working = false;
$(window).on('scroll', function(){
if($(window).scrollTop() > 1000 && !working){
working = true;
setTimeout(function(){
working = false;
}, 500);
};
});
As Tushar mentioned in the comments below your post, instead of using .delay() you could use a plain setTimeout().
On the jQuery docs for .delay() they mention that using setTimeout is actually better in some use-cases too - this is one of them.
The .delay() method is best for delaying between queued jQuery
effects. Because it is limited—it doesn't, for example, offer a way to
cancel the delay—.delay() is not a replacement for JavaScript's native
setTimeout function, which may be more appropriate for certain use
cases.
Using setTimeout your code would look like this:
var targetOffset = $(".clients").offset().top;
var $w = $(window).scroll(function() {
if ($w.scrollTop() > targetOffset - 500) {
$('.home .clients img').each(function(index) {
setTimeout(function() {
$(this).css('opacity','1');
}, (500 * index));
});
}
});
Also, you can unbind an event using .off()
so in your if ($w.scrollTop() > targetOffset - 500) { ... }
you could add a line that looks like this:
$(window).off('scroll');
Which would unbind the scroll handler from the window object.
You could also use .on() to reattach it again some time later. (with on() you can bind multiple events in one go, allowing you to write the same code for multiple handlers once.)
Please change your jquery code with following it will trigger event one time only and may be as per your reuirements :-
var targetOffset = $(".clients").offset().top;
var $w = $(window).scroll(function () {
if ($w.scrollTop() == 1300) {
console.log('here!');
$('.clients img').each(function (index) {
$(this).delay(5000 * index).css('opacity', '1');
});
}
});
Here i have take scroll hight to 1300 to show your opacity effect you can take it dynamically, if you want it 500 then please change the css as following also.
.scroll {
height:700px;
}

Fade in or fade out based on scroll

$(document).scroll(function () {
var y = $(this).scrollTop();
if (y > 397) {
$('#aboutNav.fixed').fadeIn(500);
} else {
$('#aboutNav.fixed').hide();
}
});
As you can tell, this shows a fixed navigation. The CSS is fine, the positioning is great. However I want the navigation to become visible above 397px which it does fine.
However I want the navigation to fade in when I start scrolling:
.fadeIn(500);
When the user starts stops to look at content or whatever, I want the element to fade out
.delay(3000).fadeOut(350);
I believe this is something that can be done by doing an if statement within the first if statement. However a script to check if the user is scrolling and the working script above seem to collide.
Ideas, anyone?
If I understand you correctly. You want the nav to fade in if its above 397px and only when its scrolling... So this function will do that. If I misunderstood your question please clarify in the comments
$(window).scroll(function() {
clearTimeout($.data(this, 'scrollTimer'));//Lets the timer know were scrolling
//Hide/Show nav based on location
var y = $(this).scrollTop();
if (y > 397) {
$('#aboutNav.fixed').fadeIn(500);
} else {
$('#aboutNav.fixed').hide();
}
//TimeOut function that is only hit if we havent scrolled for 3 Seconds
//In here is where you fade out the nav
$.data(this, 'scrollTimer', setTimeout(function() {
$('#aboutNav.fixed').fadeOut();
console.log("Haven't scrolled in 3s!");
}, 3000));
});
JAN 23 UPDATE based on your comment
You can add this to you $(document).ready() function
$("#elementID").hover(function(){
//show here (mouse over)
$("#elementToShow").show();
},function(){
//Start timeout here, (mouse out)
setTimeout(function() {
$("#elementToHide").hide();
}, 3000);
}
Expanding on what Kierchon's answer a bit:
Since there's no real way to tell when the user is done scrolling (i.e. no event for 'finished scrolling') you'll have to use a event-delaying method called debouncing.
Debouncing is basically setting a timeout to run some code (a function) in the future, and if the event calling the debounced function get called again, you clear and reset the timeout, doing this repeatedly until the event finally stops being called. This method is to prevent events that fire repeatedly (such as scroll and resize) to only execute things after the final event fires and your delayed (debounced) code finally executes.
Here is a nice article on use of debouncing methods in JS.
As long as I understand what you need (which I think I do) - Here's a JSBin with some working code

Detect scroll events with bootstrap-modal modalOverflow?

I have a number of tooltips a date pickers used in my modal. How can I detect if the overflow modal has been scrolled so I can either reposition any open floating elements and reposition them according to the modal scroll position?
Thx
window.scroll is not firing!
An example of this is available here: Long modals (bottom of page)
http://jschr.github.io/bootstrap-modal/
OK, I sorted it.
The scroll event doesn't propagate to the document level of the DOM so $(document).on doesn't work.
I got around it with this hack.
This did work.
$(document).on("shown", "#modalcontact", function() {
$(".modal-scrollable").unbind("scroll");
$(".modal-scrollable").scroll(function(){
//do stuff
});
});
This didn't work.
$("#modalcontact").modal({
shown: function (){
$(".modal-scrollable").scroll(function(){
//do stuff
});
}
});
This didn't work.
$(document).on("scroll", ".modal-scrollable", function(){
//do stuff
});
You already answered your own question, but I would add that it's working this way as well:
$("#modalcontact").modal().on('loaded.bs.modal', function(){
$(this).parents('.modal-scrollable').scroll(function(){
//Do stuff
});
});
I've struggled to manage to work with shown event, but it was because the content was loaded remotely.
Try
$(document).on('scroll', '.modal-scrollable', function(){
//your code here
});
The scroll event handler can be bound to more than just the window.
This worked for me, whereas the earlier answers didn't for some reason. But I am opening the modal window using code, so that I can dynamically fill it with content before it is shown.
$('#modalcontact').modal('show');
$(".modal-scrollable").unbind("scroll");
$(".modal-scrollable").scroll(function () {
$('body').append('Hey hey hey!');
});

How can I prevent the page from scrolling down when using jQuery UI hide("slide")?

here is my code :
$('#pagelinks > a').click(function () {
$('html,body').animate({ scrollTop: 0 }, 200);
setTimeout(function() {$('#my_div').hide("slide",{direction:"right"},500);},250);
return false;
});
My problem is this : When I click on a link, it scrolls up at the top correctly but then automatically scrolls down ( seems to be around where I clicked ) and hide the content of my_div by sliding it and stay there.
I don't want it to scroll down to where I clicked but rather stay at the top. I tried everything I know but nothing works.
Note that if I put just hide() instead of hide("slide",{direction:"right"},500) there is no scroll down. Plus the scroll down occurs on Firefox and Opera but not in Chromium.
Thanks for your help,
Nolhian
I can think of two options:
1) Don't use a-links with anchors if you don't use the anchor part the way it was ment to.
2) stop the default event from occuring by passing on event to the click function and using preventDefault.
example:
.click(function(e){ e.preventDefault(); });

Categories