animate scrollTop fires scroll event - javascript

I have some code that listens to the scrolling of a page and it's responsible for two things, performing the necessary action (which works) when the "page" has changed but also animate the scrollTop to the nearest "page" but in doing so the scroll event is fired so it sequentially crawls through all the "pages" until it reaches the end of the document.
How can I stop animate scrollTop from firing the scroll event? Is it even possible?
"pages" because this is an iPad html page and each 1024x768 view is a "page"

You can find a answer at this post : https://stackoverflow.com/a/1659231/237838
You could make write your own code to set the animation value, and set
a flag indicating that the change comes from an animation.
For example: (Untested)
var scrollAnimating = false
jQuery.fx.step.scrollTop = function(E) {
scrollAnimating = true;
E.elem.scrollTop = E.now;
scrollAnimating = false;
};
$('#gototop').click(function() {
$('body').animate({scrollTop:0},3000);
$(window).scroll(function () {
if (!scrollAnimating)
$('body').stop();
});
return false;
})

Related

Fire jQuery when breakpoint is reached

I have a responsive design with multiple breakpoints. Some of the block dimensions in the content are calculated with jQuery. When the viewport changes these dimensions change thus the calculation should be run. How can I fire these events when the dimension of the reference element changes? The reference element changes when a breakpoint is crossed.
I've looked at the "orientationchange" event but it's not having the results I need.
You provide very little specifics and no code so all we can do is answer very generally.
Usually, you install a .resize() event handler and on every resize of the containing window, you check to see if the resulting dimensions have changed such that you need to recalculate and modify the layout.
$(window).resize(function(e) {
// check dimensions here to decide if layout needs to be adjusted
});
jQuery mobile supports the orientationchange event like this which also gives you e.orientation as "portrait" or "landscape":
$(window).on( "orientationchange", function(e) {
// check dimensions here to decide if layout needs to be adjusted
});
There are no DOM events for watching a size change on a specific element in the page other than a window object. Instead, you have to watch whatever other events might cause a given element to get resized which might be a resize of the window, an orientation change or some other action in the page that modifies the page (a button press or click on something, for example). Then, when those other events fire and get processed, you can then check the size of your target element and see if it changed.
Here's a jQuery plugin that debounces the resize event so it only tells you about a resize when the size has stopped changing:
(function($) {
var uniqueCntr = 0;
$.fn.resized = function (waitTime, fn) {
if (typeof waitTime === "function") {
fn = waitTime;
waitTime = 250;
}
var tag = "resizeTimer" + uniqueCntr++;
this.resize(function () {
var self = $(this);
var timer = self.data(tag);
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
self.removeData(tag);
fn.call(self[0]);
}, waitTime);
self.data(tag, timer);
});
}
})(jQuery);
Working demo: https://jsfiddle.net/jfriend00/k415qunp/
Sample usage:
$(window).resized(function() {
// put code here to act when window stopped getting resized
});
This page might help you. They talk about JS execution based on breakpoints and doing it with cross-browser support. Basically you'll be using a hidden pseudo element using the "content" property of .myClass:after.

ngSwipe and horizontal scroll

I'm having issues combining ng-swipe and horizontal scrolling on mobile. The use case is that I have a page that on swiping should load next or previous and inside there are modules that show a lot of information. Some of it is scrolled.
So, as soon as you scroll the swipe on the parent kicks in and you get navigated. So I put another pair of ng-swipe on the parent of the scrollable element with this sort of trickery:
self.onInnerSwipe = function($event) {
$event.originalEvent.preventAction = true;
};
And then on the parent:
var shouldActionProceed = function($event) {
return !$event || !$event.originalEvent || !$event.originalEvent.preventAction;
};
self.goToPrev = function($event) {
if (shouldActionProceed($event)){
// Do Magic
}
}
This does the trick in the way that the action doesn't proceed if I'm swiping over that element but the scroll doesn't really work. It sorts of but it doesn't. It starts a bit and then stops.
On Chrome there are this warnings being logged sometimes.
Ignored attempt to cancel a touchmove event with cancelable=false, for
example because scrolling is in progress and cannot be interrupted.
I have prepared a demo here: http://jsbin.com/webologavu/2/ which is overly simplistic but you can reproduce the issue.
Any hints?
I think that it's a concurrency issue with these events. It might work better if you your parent event doesn't rely on the child event. To achieve that:
//add a identifier to your list element
<ul class="myList" your-other-attrs></ul>
//should proceed can rely on the target element to find out
//if the target element belongs (or is) in your list.
var shouldActionProceed = function($event) {
return !$($event.target).hasClass("myList") && //is myList?
$($event.target).parents(".myList").length == 0; //has parent 'myList'?
};
This way, the parent event can work on its on.

detect page jump to a specific element ID

After a user preform a certain action, the page reloads and it adds a #someId to the URL so the URL will be something like localhost/panel/mypage.php#someId and as a default action, the browser will jump to an element with the id of someId.
What I would like to do is to catch that using jQuery and then instead of jumping right to the #someId element, jump 100px above it and have the ability to add a smooth scrolling.
Is that possible?
There is this hashchange event of the 'window' Document Object that's exactly what you require to catch this behavior. You can use:
Javascript solution:
window.addEventListener('hashchange', function(){
// smooth scroll code
});
jQuery solution (v1.8+):
jQuery(window).on('hashchange', function(){
// smooth scroll code
});
Note: The hashchange event gets triggered on url hash change (location.hash) on the same page but not from a different page e.g. going from www.example.com/about.html#first to www.example.com/contact.html#second won't trigger the hashchange event.
This should get you started:
var a_hash = window.location.hash;
var offset = $(a_hash).offset();
if(offset.top > 100){
offset.top = offset.top - 100;
}
var body = $("html, body");
body.animate({scrollTop: offset.top}, '500', 'swing', function() {
});

Reposition page on window resize

I'm using scrollTo() for page scrolling. One problem I found is, when I resize browser, page don't scroll again to element I specified, but it stays somewhere in middle, so I have to click 'scroll' button again to align the page. Is there any way to align page when user resize browser.
I tried using this:
window.onresize = function() {
scrollToPosition(section[position]);
}
// position is variable which I declared above this event
But this makes scrolling crazy, the page start to move right/left really fast which is not normal. I believe it binds onresize event every time I resize browser.
Is there any solution for my problem
EDIT:
This is jsFiddle, but it seems I don't know how to use jsFiddle since nothing works here: http://jsfiddle.net/52eRj/1/
You can avoid reruning function everytime the resize event is executed by writing code as below. scrollToPosition function will be executed every 1 second when scrolling.
var last = new Date().getTime();
var interval = 1000; // Set your own time.
window.addEventListener('resize', function() {
var curr = new Date().getTime();
if (curr - last > interval) {
last = curr;
scrollToPosition(section[position]);
}
});
The problem might be that you are calling your scrollToPosition function on every resize event, which can be fired 100 times in a normal manual resize.
To avoid this you can use clearTimeout like this:
$(window).resize(function () {
clearTimeout(resizeId);
resizeId = setTimeout(doneResizing, 500);
});
function doneResizing() {
scrollToPosition(section[position]);
}
This way the doneResizing function would only be called after 500 miliseconds since the window has stopped resizing, avoiding therefore, those tens or hundreds of unnecessary calls.

Javascript: do an action after user is done scrolling

I'm trying to figure out a way to do this. I have a list of boxes, each about 150px high. I am using javascript (and jquery) and want that, after a user scrolls down a page, the page will auto scroll so that the boxes line up with the rest of the page (that is to say, if the user scrolls and the y position of the page is not divisible by 150, it will scroll to that nearest point).
Now, I at the moment, I know I can activate an event using the .scroll() jquery event, and I can make it move to a certain point using .scrollTop(). But every pixel the user moves the scroll bar activates the whole function. So is there a way to delay the function from firing until the user hasn't scrolled, and if they should begin to scroll again, the function will halt?
As you are already using jQuery, have a look at Ben Alman's doTimeout plugin which already handles the debouncing of methods (which is what you are after).
Example shamelessly stolen from his website:
$(window).scroll(function(){
$.doTimeout( 'scroll', 250, function(){
// do something computationally expensive
});
});
This is basically the same as Šime Vidas' answer, but less complex:
var scrollTimeout = null;
$(window).scroll(function(){
if (scrollTimeout) clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(function(){yourFunctionGoesHere()},500);
});
500 is the delay. Should be ok for mouse scroll.
Sure, in the event handler for the scroll event, fire off a setTimeout for 100 or 200 milliseconds later. Have that setTimeout function you set inside of the scroll event handler do the positioning logic you mention above. Also have the scroll event handler clear any timeouts set by itself. This way, the last time the scroll event fires, the setTimeout function will get to complete as the scroll event has not cleared it.
The code:
var scrollTimeout = null;
var scrollendDelay = 500; // ms
$(window).scroll(function() {
if ( scrollTimeout === null ) {
scrollbeginHandler();
} else {
clearTimeout( scrollTimeout );
}
scrollTimeout = setTimeout( scrollendHandler, scrollendDelay );
});
function scrollbeginHandler() {
// this code executes on "scrollbegin"
document.body.style.backgroundColor = "yellow";
}
function scrollendHandler() {
// this code executes on "scrollend"
document.body.style.backgroundColor = "gray";
scrollTimeout = null;
}
This would be a scenario, where vanilla JavaScript would be useful.
var yourFunction = function(){
// do something computationally expensive
}
$(window).scroll(function(){
yfTime=setTimeout("yourFunction()",250);
});

Categories