Click event not firing with overflow: scroll - javascript

This problem occurs in the stock browser included with at least Android 4.1.2 (not Mobile Chrome) and the WebView component in a cordova-based android app we're building.
I've built a page with a fixed header at the top of the view that contains a horizontally scrollable set of tabs with the basic DOM and inline CSS below, and click handlers attached to each of the tabs are not firing.
<html>
...
<body>
<div>
<header class="navheader" style="position: fixed; z-index: 1000;">
<h1>....</h1>
<nav style="width: 100%; overflow: scroll; -webkit-overflow-scrolling: touch;">
<div class="tabs">
<div class="tab">...</div>
<div class="tab">...</div>
<div class="tab">...</div>
<div class="tab">...</div>
<div class="tab">...</div>
<div class="tab">...</div>
...
</div>
</nav>
</header>
<section>
...
</section>
</div>
</body>
</html>
I've tried attaching a click handler in several ways with jQuery, such as:
$('body').on('click', 'header .tab', function(event){ ... });
or
$('.tabs .tab').on('click', function(event){ ... });
along with variations on the selector like 'header .tabs a', 'header .tabs .tab a', and 'header a'. I also tried:
$('.tabs .tab a').each(function(i) { this.onclick=function(){ ... }; });
and adding the onclick attribute to each a tag:
<div class="tab">...</div>
None these worked.
Using this code, though:
$('body').on('click', function(event){
console.log("Click" + $(event.target).attr('class'));
});
The click event will print 'navheader' or whatever is behind the element with 'overflow: scroll' set. Adjusting the z-index for each tab, the tabs container, and/or the nav elem had no effect on this either.
Removing 'overflow: scroll' from the CSS alleviates the problem and the events fire with any of the methods for registering a handler (the '-webkit-overflow-scrolling: touch' seemed to have no effect). But then I obviously lose the ability to scroll horizontally. Thus, it seems like elements with scrollable inner content are in some way removed from the event bubbling hierarchy. It also works in Mobile Chrome and all things iOS.
Has anyone found a work-around?
Also, webView.getSettings().setJavaScriptEnabled(true); is declared in for WebView.

I ended up essentially doing my own hit detection:
$('body').on('click', '.navheader', function(event) {
var $nav = $('nav'), x = event.pageX || event.clientY, y = event.pageY || event.clientY;
y -= $(window).scrollTop();
// Because the nav bar takes up the whole width for us
if (y > $nav[0].offsetTop && y < $nav[0].offsetTop + $nav.outerHeight()) {
var scroll_left = $nav[0].scrollLeft, click_offset = scroll_left + x,
$tabs = $nav.find(".tab");
// Since each tab has a different width
$tabs.each(function(i) {
if (click_offset >= this.offsetLeft && click_offset < this.offsetLeft + this.offsetWidth) {
// Hurray, we clicked a tab, do something like .click()
}
});
}
});

Related

Use jQuery to click anywhere and remove 'active' class

I'm having some trouble figuring out how to close a div by clicking anywhere on the screen.
I'm currently toggling an 'active' class in order to display a drop down div, then attempting to remove that class by clicking on the body:
$(document).ready(function () {
$('.navbar a').click(function () {
$(this).next('.navbar-dropdown').toggleClass('active');
});
$(body).click(function() {
if($('.navbar-dropdown').hasClass('active')){
$('.navbar-dropdown').removeClass('active');
}
});
});
<ul class="navbar">
<li>
Link
<div class="navbar-dropdown">
Dropdown Content
</div>
</li>
</ul>
However they are conflicting with each other, so as soon as the class is toggled on, the 'body' click toggles it off at the same time. Have spent some time looking on here and came across this method a few times:
$(document.body).click( function() {
closeMenu();
});
$(".dialog").click( function(e) {
e.stopPropagation();
});
However any attempts to configure this to work correctly seemed to fall on deaf ears!
The click event from the navbar is bubbling up to the body, so both events fire. stopPropagation() is one way to prevent that, but you need to do it in the navbar link's event handler, so it stops that particular event; not in a separate event handler as you had it.
Another change you might consider making is to only assign the body click handler when you need it, instead of firing all the time -- create that handler inside the navbar's click handler, and deactivate it again when it's used:
$(document).ready(function() {
$('.navbar a').click(function(e) {
var myDropdown = $(this).next('.navbar-dropdown');
$('.navbar-dropdown.active').not(myDropdown).removeClass('active'); // close any other open dropdowns
myDropdown.toggleClass('active'); // open this one
$('body').click(function() {
// no need for an if statement here, just use a selector that matches the active elements:
$('.navbar-dropdown.active').removeClass('active');
$('body').off('click'); // cancel the body's click handler when it's used
});
e.stopPropagation(); // prevent the navbar event from bubbling up to the body
});
});
.active {
color: red
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="navbar">
<li>
Link
<div class="navbar-dropdown">
Dropdown Content
</div>
</li>
<li>
Link 2
<div class="navbar-dropdown">
Dropdown Content 2
</div>
</li>
<li>
Link 3
<div class="navbar-dropdown">
Dropdown Content 3
</div>
</li>
</ul>
(If there's a chance you might need more than one separate click event handler on the body, you can namespace the event so you can control which one you're turning off:
$('body').on("click.myNamespace", function() {
// do other stuff
$('body').off("click.myNamespace")
})
I did the exact thing as you and it works for me. Are you sure you don't have any other event listeners attached? Or maybe a z-index on the menu bringing it underneath other elements?
$(document).click(function(e) {
$(".dialog").text('closed')
});
$(".dialog").click(function(e) {
e.target.innerText = 'open';
e.stopPropagation();
});
.dialog {
width: 200px;
height: 200px;
background: antiquewhite;
text-align: center;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<div class="dialog">open</div>
</body>
</html>

Javascript not activating

I have a script that is made to add .fix class to a header tag with #header-wrap id once the page is scrolled a certain amount, but for some reason nothing happens on scroll.
HTML:
<header id="header-wrap">
<div id="redline"></div>
<div id="velkommen"></div>
<div id="header">
<div id="indre">
<h1 id="logo">MCBERGBYS</h1>
</div>
</div>
</header>
<script>
var wrap = $("#header-wrap");
wrap.on("scroll", function(e) {
if (this.scrollTop > 143) {
wrap.addClass("fix");
} else {
wrap.removeClass("fix");
}
});
</script>
I'm very new to javascipt so I bet something obvious is off. Any help is appreciated, thank you.
You need to bind your .on('scroll') event to the $(window), not to your #header-wrap element. This will check when the document is being scrolled up and down, as opposed to seeing when an individual element is being "scrolled" (like when you move up and down in a textarea).

Unfold Submenu conditions (jQuery)

I'm stuck with a jQuery issue that I don't manage to solve.
I've created a menu with sub menu elements. I would like to toggle the height of content by clicking in menu items. The thing is when I click on other item, the content collapse. Kind of tricky to explain, I've put two websites doing the job
http://www.polerstuff.com/ -> When you click on 'shop' and then on 'info', the sub menu stays open. The same trick was seen here http://topodesigns.com/
I guess these two websites are using Shopify.
$(document).ready(function() {
$(".button").on("click", function() {
if($(".content").height() == 0) {
$(".content").animate({height: "300px"});
}
else if($(".content").height() == 300) {
$(".content").animate({height: "0px"});
}
});
});
Here is my jsfiddle
-> Thank a lot in advance.
Here's version of your fiddle that uses the data attribute to target divs with desired content, and another data tag containing desired heights to animate (but there are many other ways).
Clicking on the same button toggles it shut, this is achieved by adding an indicative class.
The 'hiding' divs may contain further divs with classes and layout as required.
$(document).ready(function (){
$(".b").on("click", function (){
var $this = $(this),
target = $this.data('target'),
tall = $this.data('tall'),
content = $(".content");
target = $('.'+target).html(); // get the html content of target divs
content.html(target); // insert said content
if (!$this.hasClass('on')) { // if it hasn't been clicked yet..
$(".b").removeClass('on'); // say that none have been clicked
$this.addClass('on'); // say that just this one has been clicked
content.animate({height: tall}, 200); // animate to the height specified in this buttons data attribute
} else {
content.animate({height: "0px"});
$this.removeClass('on');
}
});
});
.content {
background: coral;
width: 100%;
height: 0px;
overflow:hidden;
}
.hiding{
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<button class="b" data-target="alpha" data-tall="4em">Button</button>
<button class="b" data-target="bravo" data-tall="7em">Button</button>
<button class="b" data-target="charlie" data-tall="5em">Button</button>
<div class="content">Le contenu</div>
<div class="hiding alpha"> some stuff </div>
<div class="hiding bravo"> other things </div>
<div class="hiding charlie"> bits and pieces </div>

Jquery show/hide divs - fix overlapping animations

I am using JS to show/hide divs via clicking on the side nav with jquery functions fadeIn() and fadeOut(). The problem I run into is as one div fades out, the next is fading in simultaneously. Also, if I click the link for the div that is already shown, it fades out and fades in again. I'm not sure if an IF statement would be the best approach to do two fixes:
1. Let shown div fully fadeOut before next starts to fadeIn.
2. Currently shown div will not fadeOut/In if same link is clicked.
Here is what I have thus far (without my broken attempt at an IF statement):
http://jsfiddle.net/k55Cw/1/
HTML:
<div class="container">
<header>
<ul class="sidenav">
<li><h2><a data-region="nav-1" href="#">About</a></h2></li>
<li><h2><a data-region="nav-2" href="#">Services</a></h2></li>
<li><h2><a data-region="nav-3" href="#">Team</a></h2></li>
<li><h2><a data-region="nav-4" href="#">News</a></h2></li>
<li><h2><a data-region="nav-5" href="#">Contact</a></h2></li>
</ul>
</header>
<div id="nav-1" class="infozone"><p>Hello I'm box 1.</p></div>
<div id="nav-2" class="infozone"><p>Hello I'm box 2.</p></div>
<div id="nav-3" class="infozone"><p>Hello I'm box 3.</p></div>
<div id="nav-4" class="infozone"><p>Hello I'm box 4.</p></div>
<div id="nav-5" class="infozone"><p>Hello I'm box 5.</p></div>
</div>
CSS:
.infozone{
float:left;
height:400px;
width:800px;
background-color: #000;
display:none;
}
JS:
$(document).ready(function() {
$('.sidenav a').click(function(){
$('.infozone').fadeOut(850);
var region = $(this).attr('data-region');
$('#' + region).fadeIn(850);
});
});
to chain the animations put the fadeIn inside the callback for fadeOut, and to cancel the function if it's currently shown, check if the div is already visible.
I've also had to add a check to see if the current .infozone div is visible - or else the fadeOut applies to hidden elements too, and the callback fires multiple times:
$(document).ready(function() {
$('.sidenav a').click(function(){
var region = $(this).attr('data-region');
var $region = $('#' + region);
if ($region.is(':visible')) return;
var $infozone = $('.infozone:visible');
if ($infozone.length === 0) {
$region.fadeIn(850);
} else {
$infozone.fadeOut(850, function() {
$region.fadeIn(850);
});
}
});
});
You could something like that:
html
This make you page works when javascript is disabled:
<header>
<ul class="sidenav">
<li><h2>About</h2></li>
<li><h2>Services</h2></li>
<li><h2>Team</h2></li>
<li><h2>News</h2></li>
<li><h2>Contact</h2></li>
</ul>
</header>
note that the href point to the id you want to show. This will works also for screen reader if you want to make your page accessible.
javascript. I have not tested it, you might have to fix few things, but the idea is there
$(document).ready(function() {
$('.sidenav a').click(function(e){
var href = $(this).attr('href');
// prevent default
e.preventDefault();
// prevent clicked twice
if(!$(this).hasClass('active'){
$('.sidenav a').removeClass('active');
$(this).addClass('active'){
$('.infozone').fadeOut(850);
$(href.substring(1)).fadeIn(850);
}
});
You should also consider adding some ARIA attributes and roles attributes.

Sliding a div / modifying a css property when using touch on an ipad

What im looking to achieve is to modify the margin-left css property of a div when someone slides their finger across the div on an ipad.
To explain what i'm trying to do, I have setup this page:
http://littleirrepressiblewonton.com/wp7/category/all/
Now when someone clicks on a thumbnail image, it loads a horizontal slideshow of large images. Some of the images are too wide to fit on the ipad and they wish to use touch to drag this horizontal slideshow of images left or right.
The way the divs are setup are as follows:
<div class='WontonGalleryFullsMask'>
<div class='WontonGalleryFulls' data-animating='no'>
<div class="WontonGalleryFullImage" data-idx="0" ><img src="http://littleirrepressiblewonton.com/wp7/wp-content/uploads/cache/VP_test_poster022/2835976114.jpg" alt="VP_test_poster022" /></div>
<div class="WontonGalleryFullImage" data-idx="1" ><img src="http://littleirrepressiblewonton.com/wp7/wp-content/uploads/cache/VP_test_poster021/663128145.jpg" alt="VP_test_poster021" /></div>
<div class="WontonGalleryFullImage" data-idx="2" ><img src="http://littleirrepressiblewonton.com/wp7/wp-content/uploads/cache/VP_test_poster020/3945564367.jpg" alt="VP_test_poster020" /></div>
</div>
</div>
The div.WontonGalleryFullsMask has the following css and is setup as a mask.
height: 523px;
overflow: hidden;
width: 100%;
and then the margin-left property of the div.WontonGalleryFulls div is modified to move the gallery left and right.
So if someone slides 300px on the ipad, I need to modify the margin-left css property of the div.WontonGalleryFulls
I'm looking for a jquery solution as the site is already using it.
i ended up modifying a script from http://popdevelop.com/2010/08/touching-the-web/
$.fn.draggable = function() {
var offset = null;
var start = function(e) {
var orig = e.originalEvent;
var ml = parseInt($(this).css('margin-left'));
offset = {
x: orig.changedTouches[0].pageX - ml //pos.left
};
};
var moveMe = function(e) {
e.preventDefault();
var orig = e.originalEvent;
$(this).css({
'margin-left': orig.changedTouches[0].pageX - offset.x
});
};
this.bind("touchstart", start);
this.bind("touchmove", moveMe);
};
$('div.WontonGalleryFulls').css('position', 'absolute');
$('div.WontonGalleryFulls').draggable();

Categories