when dragging horizontal carousel left to right on touch device it also allows it to be dragged up and down which jiggles the whole page around. How can I disable vertical scrolling on owl carousel.
I can post the js file if anyone can help
Thanks in advance
Awesome css3 :)
.owl-carousel
{
-ms-touch-action: pan-y;
touch-action: pan-y;
}
This seems to work for me, at least on iOS, haven't tested on Android.
When you start sliding with mouse or touch I saw that Owl Carousel adds the class .owl-grab to the slider. I then found this code from #Turnerj and just put .owl-grab in the code.
Disable scrolling when touch moving certain element
It also works with multiple sliders on same page. Hope this helps! (I'm new to jQuery so there could probably be flaws to this solution)
window.blockMenuHeaderScroll = false;
$(window).on('touchstart', function(e) {
if ($(e.target).closest('.owl-grab').length == 1) {
blockMenuHeaderScroll = true;
}
});
$(window).on('touchend', function() {
blockMenuHeaderScroll = false;
});
$(window).on('touchmove', function(e) {
if (blockMenuHeaderScroll) {
e.preventDefault();
}
});
Use hammer.js with addEventListner for Classes.
I have tested with iOS (iphoneX) and Android (Nexus 5X) and work like a charme.
I hope can help!
window.blockMenuHeaderScroll = true;
var mc = new Hammer(document);
var classname = document.getElementsByClassName("elenco_image");
mc.on("swipeleft swiperight panleft panright", function(ev) {
console.log(ev.type + " gesture detected.");
window.blockMenuHeaderScroll = true;
});
mc.on("swipeup swipedown panup pandown", function(ev) {
console.log(ev.type + " gesture detected.");
window.blockMenuHeaderScroll = false;
});
for (var i = 0; i < classname.length; i++) {
classname[i].addEventListener('touchmove', function(evt) {
if (blockMenuHeaderScroll) {
evt.preventDefault();
}
}, {
passive: false
});
}
.owl-carousel
{
-ms-touch-action: pan-x;
touch-action: pan-x;
}
This worked for me as I need only horizontal scroll. Above code restricts the vertical scroll.
This will block vertical scrolling while dragging the image horizontally,
or prevent the horizontal pan while trying to v-scroll the page itself.
Important: Attach the event directly to the IMG element.
let blockScroll = false;
let blockPan = false;
$('.owl-carousel img').on('touchstart', '', ots);
$('.owl-carousel img').on('touchmove', '', otm);
let p0 = [0,0];
function ots(ev) { //save the first touch point
p0 = [ev.touches[0].screenX, ev.touches[0].screenY];
blockScroll = false;
blockPan = false;
}
function otm(event){
if(blockScroll)
event.preventDefault(); //don't let the window v-scroll
else if(blockPan)
{ //don't let OWL get the event and pan-x.
event.stopPropagation();
event.stopImmediatePropagation();
}
else
{ //calculate distance from the first touch point on every move
let t = event.touches[0];
let dx = t.screenX - p0[0];
let dy = t.screenY - p0[1];
if( Math.abs(dx) > Math.abs(dy) )
{
blockScroll = true;
event.preventDefault();
}
else
{
blockPan = true;
event.stopPropagation();
event.stopImmediatePropagation();
}
}
}
Tested on android (Chrome) and ios(Safari).
Some improvements on #Giovanni Locombi's answer to make the touch actions smoother. Works on iOS
Using Hammer.js from https://hammerjs.github.io/
window.blockMenuHeaderScroll = false;
var mc = new Hammer(document);
var classname = document.getElementsByClassName("owl-carousel");
mc.on("swipeleft swiperight panleft panright", function(ev) {
window.blockMenuHeaderScroll = true;
});
mc.on("panend swipeend", function (ev){
window.blockMenuHeaderScroll = false;
});
mc.on("swipeup swipedown panup pandown", function(ev) {
window.blockMenuHeaderScroll = false;
});
for (var i = 0; i < classname.length; i++) {
classname[i].addEventListener('touchmove', function(evt) {
if (blockMenuHeaderScroll) {
evt.preventDefault();
}
}, {
passive: false
});
}
None of the above worked for me.
but this worked.
.owl-carousel .owl-stage, .owl-carousel.owl-drag .owl-item{
-ms-touch-action: auto;
touch-action: auto;
}
Related
Now that Bootstrap 3 is out, what is the recommended option for enabling touch? As before, there aren't many touch events in the bootstrap.js, though it is supposed to be a mobile first framework.
The last thing I've found on github suggests using fastclick.js, but that was before the v3.0 release.
My recommendation is to use Bootstrap alongside JQuery mobile, TouchSwipe, or Hammer.js . An example of a bootstrap touch carousel can be found here.
Start working on another fully working Touch Carousel on GitHub. This also includes drag events...
Despite I believe bootstrap is a joke of a css framework (especially due to no multileveled navigation), I would probably agree with others to go with some different carousel if you have a choice.
From my experience JQuery mobile will work rather smoothly but my site was not built alongside jquery mobile and the css belonging to it really messed the things up.
<script>
$(document).ready(function() {
$('.carouselresp').carousel({'data-interval': 6000, 'data-pause': "hover"});
var clicking = false;
var currentMousePos = 0;
var newMousePos = 0;
$('.carouselresp img').on('mousedown', function(event) {
clicking = true;
currentMousePos = event.pageX;
});
$('.carouselresp img').on('touchstart', function(event) {
clicking = true;
var touchstart = event.originalEvent.touches[0];
currentMousePos = touchstart.pageX;
});
$(document).on('mouseup', function(event) {
clicking = false;
});
$('.carouselresp img').on('touchend', function(event) {
clicking = false;
});
$(document).on('mousemove', function(event) {
if (!clicking) {
return;
}else {
if (event.pageX < currentMousePos) {
if ((currentMousePos - event.pageX) > 50) {
$('.carouselresp').carousel('next');
clicking = false;
}
} else {
if ((event.pageX - currentMousePos) > 50) {
$('.carouselresp').carousel('prev');
clicking = false;
}
}
}
});
$('.carouselresp img').on('touchmove', function(event) {
var touch = event.originalEvent.touches[0];
if (!clicking) {
return;
}else {
if (touch.pageX < currentMousePos) {
if ((currentMousePos - touch.pageX) > 50) {
$('.carouselresp').carousel('next');
clicking = false;
}
} else {
if ((touch.pageX - currentMousePos) > 50) {
$('.carouselresp').carousel('prev');
clicking = false;
}
}
}
event.preventDefault();
});
});
</script>
It works fine for me on android and iphone too, plus I am allowing the move event in browsers with no touch support.
I hope it helped.
TomHre
I've been working on this jQuery effect heres the fiddle:
http://jsfiddle.net/abtPH/26/
Everything's pretty good so far, however when I click on the elements too fast it seems to get buggy and get weird behavior. If you take your time and click on the elements it works fine.
I've tried using :animate
stuff to make sure the animation ends before the user can click on the next one. I do not like this approach though because from a end user it seems like the effects are laggy. I want the user to be able to click on the elements fast and have the desired effect.
Here's my jQuery so far:
$('li').on('click', function (e) {
e.preventDefault();
var active = $(this).siblings('.active');
var posTop = ($(this).position()).top;
if (active.length > 0) {
var activeTop = (active.position()).top;
if (activeTop == posTop) {
$(this).find('.outer').fadeIn('medium', function () {
active.toggleClass('active', 400).find('.outer').fadeOut('medium');
});
} else {
$(this).siblings('.active').toggleClass('active', 400).find('.outer').slideToggle();
$(this).find('.outer').slideToggle();
}
} else {
$(this).find('.outer').slideToggle();
}
$(this).toggleClass('active', 400);
});
$('.outer').on('click', function (e) {
return false;
});
Use .finish() complete all the queued animation before beginning a new one
$('li').on('click', function(e){
e.preventDefault();
var active = $(this).siblings('.active');
var posTop = ($(this).position()).top;
if (active.length > 0) {
var activeTop = (active.position()).top;
if (activeTop == posTop) {
$(this).find('.outer').finish().fadeIn('medium', function(){
active.finish().toggleClass('active', 400).find('.outer').finish().fadeOut('medium');
});
} else {
$(this).siblings('.active').finish().toggleClass('active', 400).find('.outer').finish().slideToggle();
$(this).find('.outer').finish().slideToggle();
}
} else {
$(this).find('.outer').finish().slideToggle();
}
$(this).finish().toggleClass('active', 400);
});
$('.outer').on('click', function(e){
return false;
});
Demo: Fiddle
I'm trying to make a draggable navigation. The code works fine in chrome but for some reason this code won't work in firefox:
<script type="text/javascript">
$(document).ready(function() {
$('img').on('dragstart', function(event) { event.preventDefault(); });
$('body').mousemove(function (event) {
//button clicked
if (event.which)
{
//there is a previous movement
if (window.moveEvent)
{
//difference in position since last time
var xDiff = event.screenX - window.moveEvent.screenX;
var yDiff = event.screenY - window.moveEvent.screenY;
//Move the scroll bar by the same amount as we moved the mouse
$('body').scrollTop($('body').scrollTop() - yDiff);
$('body').scrollLeft($('body').scrollLeft() - xDiff);
//$('body').addClass('grabbing');
event.preventDefault();
}
window.moveEvent = event; //store for next time
}
else
{
//$('body').removeClass('grabbing');
window.moveEvent = false; //wipe the last one
}
});
//.mouseup(function () {$('body').addClass('grabbing');});
});
</script>
any help would be much appreciated
Thanks
Any insights on how to catch a scrolling event on a element that has overflow:hidden? I would like to scroll in a column without showing a scrollbar to the user.
This is actually a somewhat indepth process. What I do is set global flags when users mouse enters and leaves the element that you want to scroll. Then, on the mousewheel event for the body I check to see if the MOUSE_OVER flag is true, then stop propagation of the event. This is so the main body doesnt scroll in case your entire page has overflow.
Note that with overflow hidden, the default scrolling ability is lost so you must create it yourself. To do this you can set a mousewheel listener on your div in question and use the event.wheelDelta property to check whether the user is scrolling up or down. This value is different according to browser, but it is generally negative if scrolling down and positive if scrolling up. You can then change position of your div accordingly.
This code is hacked up quickly but it would essentially look like this...
var MOUSE_OVER = false;
$('body').bind('mousewheel', function(e){
if(MOUSE_OVER){
if(e.preventDefault) { e.preventDefault(); }
e.returnValue = false;
return false;
}
});
$('#myDiv').mouseenter(function(){ MOUSE_OVER=true; });
$('#myDiv').mouseleave(function(){ MOUSE_OVER=false; });
$('#myDiv').bind('mousewheel', function(e){
var delta = e.wheelDelta;
if(delta > 0){
//go up
}
else{
//go down
}
});
I use overflow:scroll, but also Absolutely position a div over the scroll bar in order to hide it.
$("body").css("overflow", "hidden")
$(document).bind('mousewheel', function(evt) {
var delta = evt.originalEvent.wheelDelta
console.log(delta)
})
works for me. adapted from How do I get the wheelDelta property?
I edited #anson s answer to Vanilla Javascript since it may be useful for others. Also note that "mousewheel" event is deprecated. So my code uses "wheel" instead. Next to that I added arrow functions for practical access the to "this".
fixScrollBehavior(elem) {
elem.addEventListener('scroll', (e) => {
console.log('scrolling');
});
let MOUSE_OVER = false;
elem.addEventListener('wheel', (e) => {
if (MOUSE_OVER) {
if (e.preventDefault) {
e.preventDefault();
}
e.returnValue = false;
return false;
}
});
elem.addEventListener('mouseenter', () => {
MOUSE_OVER = true;
});
elem.addEventListener('mouseleave', () => {
MOUSE_OVER = false;
});
elem.addEventListener('wheel', (e) => {
let delta = e.wheelDelta;
if (delta > 0) {
//go up
} else {
//go down
}
});
}
Note that this does not fix the mobile touch-"scroll"s.
$("div").on('wheel', function (e) {
if (e.originalEvent.deltaY < 0) {
console.log("Scroll up");
} else {
console.log("Scroll down");
}
});
This did the trick for me.
JSFiddle
StackFiddle:
$("div").on('wheel', function(e) {
if (e.originalEvent.deltaY < 0) {
console.log("Scroll up");
} else {
console.log("Scroll down");
}
});
div {
height: 50px;
width: 300px;
background-color: black;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
I am late, but I think I have a better answer.
Style your container as overflow: overlay, this will free up space of scrollbar, then style scrollbar or hide it or make its handle height/width 0,
Then you should get scroll events also.
Note : styling the scrollbar is not supported in all web browsers.
I have a modal box window (pop-up) that contains an iframe,
and inside that iframe there's a div that is scrollable.
When I scroll the iframe's inner DIV, and it has reached its top or bottom limit, the window of the browser itself starts to scroll. this is an unwanted behavior.
I've tried something like this, which kills the main window scroll when onMouseEnter when mouse enters pop-up box area:
e.preventDefault() is not working as it should for some reason...
$("#popup").mouseenter(function(){
$(window).bind("scroll", function(e){
e.preventDefault();
});
}).mouseleave(function(){
$(window).unbind("scroll");
});
Solved (for some browsers) using a simple CSS property: overscroll-behavior:
auto
The default scroll overflow behavior occurs as normal.
contain
Default scroll overflow behavior is observed inside the element this value is set on (e.g. "bounce" effects or refreshes), but no scroll chaining occurs to neighboring scrolling areas, e.g. underlying elements will not scroll.
none
No scroll chaining occurs to neighboring scrolling areas, and default scroll overflow behavior is prevented.
body{
height: 600px;
overflow: auto;
}
section{
width: 50%;
height: 50%;
overflow: auto;
background: lightblue;
overscroll-behavior: none; /* <--- the trick */
}
section::before{
content: '';
height: 200%;
display: block;
}
<section>
<input value='end' />
</section>
Simply apply that style property on the element which the scroll should be "locked-in" to and the scroll event will not bubble up to any parent element which might have a scroll as well.
Same demo as above but without the trick:
body{
height: 600px;
overflow: auto;
}
section{
width: 50%;
height: 50%;
overflow: auto;
background: lightblue;
}
section::before{
content: '';
height: 200%;
display: block;
}
<section>
<input value='end' />
</section>
Sorry, as far as I'm aware it is impossible to cancel any kind of scroll event.
Both W3 and MSDN say:
Cancelable No
Bubbles No
I think you'll have to leave this up to browser authors to fix. Firefox (3.5 on Linux, anyway) seems to have a better behaviour for me: it only scrolls the parent if the child is already at the top/bottom end at the moment you start using the scrollwheel.
If we cannot prevent window scrolling, why not undo it?
That is, catching the scroll event and then scrolling back to a fixed position.
The following code locks the Y-Axis as long as one hovers over $("#popup"):
// here we store the window scroll position to lock; -1 means unlocked
var forceWindowScrollY = -1;
$(window).scroll(function(event) {
if(forceWindowScrollY != -1 && window.scrollY != forceWindowScrollY) {
$(window).scrollTop(forceWindowScrollY);
}
});
$("#popup").hover(function() {
if(forceWindowScrollY == -1) {
forceWindowScrollY = $(window).scrollTop();
}
}, function() {
forceWindowScrollY = -1;
});
I use this for the query suggest box on http://bundestube.de/ (enter some characters into the top search box to make the scrollable pane visible):
This works flawlessly in Chrome/Safari (Webkit) and with some scrolling glitches in Firefox and Opera. For some reason, it does not work with my IE installation. I guess this has to do with jQuery's hover method, which appears to not work correctly in 100% of all cases.
I know it's quite an old question, but since this is one of top results in google... I had to somehow cancel scroll bubbling without jQuery and this code works for me:
function preventDefault(e) {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}
document.getElementById('a').onmousewheel = function(e) {
document.getElementById('a').scrollTop -= e. wheelDeltaY;
preventDefault(e);
}
my jQuery plugin:
$('.child').dontScrollParent();
$.fn.dontScrollParent = function()
{
this.bind('mousewheel DOMMouseScroll',function(e)
{
var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail;
if (delta > 0 && $(this).scrollTop() <= 0)
return false;
if (delta < 0 && $(this).scrollTop() >= this.scrollHeight - $(this).height())
return false;
return true;
});
}
As of now in 2018 and onwards e.preventDefault is enough.
$('.elementClass').on("scroll", function(e){
e.preventDefault();
});
This will prevent scroll to parent.
That's how I solved the problem:
I call the following when I open the popup:
$('body').css('overflow','hidden');
Then, when I close the popup I call this:
$('body').css('overflow','auto');
The popup is meant to be modal so no interaction is required with the underlying body
Works pretty well
Apparently, you can set overflow:hidden to prevent scrolling. Not sure how that'd go if the doc is already scrolled. I'm also on a mouseless laptop, so no scrolly wheel testing for me tonight :-) It's probably worth a shot though.
you can try jscroll pane inside the iframe to replace the default scroll.
http://www.kelvinluck.com/assets/jquery/jScrollPane/jScrollPane.html
I am not sure, but give it a try
Here's what I do:
$('.noscroll').on('DOMMouseScroll mousewheel', function(ev) {
var prevent = function() {
ev.stopPropagation();
ev.preventDefault();
ev.returnValue = false;
return false;
}
return prevent();
});
demo fiddle
Use CSS overflow:hidden to hide the scrollbar as this will do nothing if they drag it.
Works cross-browser
New web dev here. This worked like a charm for me on both IE and Chrome.
static preventScrollPropagation(e: HTMLElement) {
e.onmousewheel = (ev) => {
var preventScroll = false;
var isScrollingDown = ev.wheelDelta < 0;
if (isScrollingDown) {
var isAtBottom = e.scrollTop + e.clientHeight == e.scrollHeight;
if (isAtBottom) {
preventScroll = true;
}
} else {
var isAtTop = e.scrollTop == 0;
if (isAtTop) {
preventScroll = true;
}
}
if (preventScroll) {
ev.preventDefault();
}
}
}
Don't let the number of lines fool you, it is quite simple - just a bit verbose for readability (self documenting code ftw right?)
I would like to add a bit updated code that I found to work best:
var yourElement = $('.my-element');
yourElement.on('scroll mousewheel wheel DOMMouseScroll', function (e) {
var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail;
if (delta > 0 && $(this).scrollTop() <= 0)
return false;
if (delta < 0 && $(this).scrollTop() >= this.scrollHeight - $(this).outerHeight())
return false;
return true;
});
The difference between this one and one that is already mentioned above is the addition of more events and the usage of outerHeight() instead of height() to avoid crashing if element has padding!
$('.scrollable').on('DOMMouseScroll mousewheel', function (e) {
var up = false;
if (e.originalEvent) {
if (e.originalEvent.wheelDelta) up = e.originalEvent.wheelDelta / -1 < 0;
if (e.originalEvent.deltaY) up = e.originalEvent.deltaY < 0;
if (e.originalEvent.detail) up = e.originalEvent.detail < 0;
}
var prevent = function () {
e.stopPropagation();
e.preventDefault();
e.returnValue = false;
return false;
}
if (!up && this.scrollHeight <= $(this).innerHeight() + this.scrollTop + 1) {
return prevent();
} else if (up && 0 >= this.scrollTop - 1) {
return prevent();
}
});
Try the below code:
var container = document.getElementById('a');
container.onwheel = (e) => {
const deltaY = e.wheelDeltaY || -(e.deltaY * 25); // Firefox fix
container.scrollTop -= deltaY;
e.preventDefault();
e.stopPropagation();
e.returnValue = false;
};
function stopPropogation(e)
{
e = e || window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
if (e.preventDefault) e.preventDefault();
}
This should work.