click event is triggered by scrolling - javascript

in my js code I have pretty simple event listener listening for a click -
element.addeventlistener('click', ()=>{
#do somthing
})
the issue is that when I am scrolling on IOS (iphone) - touching this element to start the scroll, triggers the event listener.
Is there a way to prevent a event listener on iphone, unless no scrolling is to follow?
i.e. do something if clicked but scrolling doesn't follow
alternatively the might be a completely different solution (but I am trying to avoid a library)
thanks
W
ANSWER
After reviewing the answer given below (which does work) as described, this issue was still persisting. This gave me cause to review my CSS on which I found that on IOS mobile (iphone) - the CSS psudo selector :focus is activated when you scroll over an item.
I added a media query to only allow :focus to be used on desktop size devices or above, which solved the issue.

I have a found a possible solution on another question in Stackoverflow: Question
Basically you add a scroll listener to your window. This will then set a global boolean called disable_click_flag to true when scrolling. If the user wasn't scrolling for at least 250ms it will be set to false.
When the boolean is true then the click event isn't able to go trough.
var disable_click_flag = false;
var timeout = null;
window.addEventListener('scroll', () => {
disable_click_flag = true;
if(timeout) clearTimeout(timeout);
timeout = setTimeout(function(){ disable_click_flag = false }, 250);
}
element.addeventlistener('click', () => {
if(disable_click_flag === false{
#do somthing
}
})

I'm not an expert, but I would try:
var prevScroll = pageYOffset;
window.addEventListener("scroll", () => prevScroll = pageYOffset);
window.addEventListener("click", (e) => {
if (pageYOffset !== prevScroll) return;
// your code
});
Please note that this code is not tested, however I think it should work.

Related

Prevent child event from firing

I have a slider that I am currently making. I am making slow progress, but I am making progress nonetheless!
Currently I have this:
http://codepen.io/r3plica/pen/mEKyGG?editors=1011#0
There are 2 things you can do with this control, the first thing is you can drag left or right. The second thing you can do is click a "point" and it will scroll to the center.
The problem I have is that if I start dragging from a point, when I let go it will invoke the moveToCenter method.
I have tried to prevent this by adding
// Stop from accessing any child events
e.preventDefault();
e.stopPropagation();
to the end of the dragEventHandler, but this did not work.
I also have 2 boolean values options.drag and options.start. I though I might be able to use them somehow (if the drag has started and is enabled then don't perform the moveToCenter but this didn't work either.
Do anyone have any idea how to get this to work?
Maybe this will help. You can register your events in bubbling or capturing mode, using addEventListener method. It defines orders of processing your events - child -> parent (bubbling), or vice versa (capturing).
http://www.quirksmode.org/js/events_advanced.html
So, if you use addEventListener(event, handler, true), it will use capturing event mode.
Codepen:
http://codepen.io/anon/pen/bZKdqV?editors=1011
divs.forEach(function (div) {
div.addEventListener('click', function(e) {
e.stopPropagation();
console.log('parent');
}, true);
});
Be aware of browser support (IE9+). All modern browsers - yes, of course.
http://caniuse.com/#search=addeventlistener
Update
So it turned out to be easier than first approach. (no need for capturing)
Check out codepen:
http://codepen.io/anon/pen/QExjzV?editors=1010
Changes from your sample:
At the beginning of moveToCenter: function(e, options, animate) function
if (options.started) {
return;
}
In if (['mouseup', 'mouseleave'].indexOf(e.type) > -1):
setTimeout(function() {
options.started = false;
} , 100);
instead of
options.started = false;
Hope this helps.

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.

How to disable scrolling and re-enable scrolling on a mobile touch screen device

This is not so much of a question as it is an solution to the question.
It was difficult find a solution until I stumbled across the answer in added by hallodom (How to disable scrolling temporarily?) which was responding to a slightly different problem.
I wanted to explicitly document an answer to the problem. Other solutions are most welcome and would add to the conversation.
hallodom's solution was:
For mobile devices, you'll need to handle the touchmove event:
$('body').bind('touchmove', function(e){e.preventDefault()})
And unbind to re-enable scrolling. Tested in iOS6 and Android 2.3.3
$('body').unbind('touchmove')
I used hallodom's solution by simply attaching them to functions called when an object in my DOM was clicked:
$('body').on('click', 'button', function(e){
if($(this).prop('checked')){
disable_scroll();
}else{
enable_scroll();
}
});
function disable_scroll() {
$('body').bind('touchmove', function(e){e.preventDefault()});
}
function enable_scroll() {
$('body').unbind('touchmove');
}
Try this code :
var scroll = true
$(document).bind('touchmove', function(){
scroll = false
}).unbind('touchmove', function(){
scroll = true
})
$(window).scroll(function() {
if ($('button').is(':checked') && scroll == false) {
$(document).scrollTop(0);
}
})

Scroll event doesn't fire unless page moves

I'm looking to get an event to fire when one scrolls "up" from $(window).scrollTop == 0.
If you have the following code:
$(window).scroll(function(){
console.log("scrolling")
});
On a page where the document < window height then that event never fires because $(window).scrollTop isn't changing, but this doesn't mean that there's no mouse scroll input. I want an event to fire on mouse scroll regardless if the page is moving or not.
Seems like what you are looking for:
http://jsfiddle.net/n8eVQ/
$(document).on('mousewheel DOMMouseScroll MozMousePixelScroll', function(event, delta) {
console.log('mousewheel');
//you could trigger window scroll handler
$(window).triggerHandler('scroll');
});
Other way is to capture scroll event on modern browsers which support event capturing phase (IE>8). This can be used for any dynamic element. As jQuery doesn't implement capturing phase, you have to use javascript addEventListener() method. Here an example implementing logic to get scrolling direction for a textarea:
document.addEventListener('scroll', function (event) {
var $elm = $(event.target);
if ($elm.is('textarea')) { // or any other filtering condition
// do some stuff
var direction = $elm.scrollTop() > ($elm.data('scrollTop') || 0) ? "down" : "up";
$elm.data('scrollTop', $elm.scrollTop());
console.log('scrolling', direction);
}
}, true);
-DEMO-
document.addEventListener('DOMMouseScroll', callbackFunction, false);
Solution for firefox; for other browsers see #roasted solution

jQuery: Prevent stacking animations

I know there are several other posts with solutions to this, but my current problem is a little different.
I have two events on an element - mouseenter and mouseleave. The first changed the color of my element to light and the other back to dark, this makes a flashing effect.
The problem is when I go in and out a couple of times the events stack and it flashes many times even if no new events are triggered. I would like to prevent that, but .stop() does not help.
Here's the catch: I would like to trigger 1 flash no matter what, but not more than 1. So when someone moves in / out - the event mouseenter will be fired, after it mouseleave and after it nothing.. until another in / out is triggered.
I guess this could be made by locking (not listening for) new events when in / out is triggered up until the effect has finished, but I don't know how to do without unbinding and binding it again. Isn't there any lockEvent() or something?
Have you already used .stop(true) or .stop(true, true)?
there is pseudo-class in jQuery ":animated"
you can use it on first mouseenter even like:
if ( $(this).is(':animated')) {
return false;
}
to prevent additional animation
You can try just setting a bool var and firing only if false...
var anim = {
animating: false,
over: function(){
if(!anim.animating)
{
anim.animating = true;
// do you animation here
// and set your animating bool to false before calling outro...
$('#elem').animate({/*some css change*/ }, 1000, function(){
anim.animating = false;
anim.out();
});
}
},
out: function(){
if(!anim.animating)
{
anim.animating = true;
//do your outro animation here
$('#elem').animate({/*some css change*/ }, 1000, function(){
anim.animating = false;
});
}
}
};
then have your listener call anim.over and anim.out...
$('#elem').on('mouseenter', function(){
anim.over();
}).on('mouseleave', function(){
anim.out();
});
This way you will call animation on enter and it will automatically fire off the outro animation when the intro completes.

Categories

Resources