Prevent child elements from firing hard coded click event of parent elements - javascript

I have a div class called 'cat'. In mouseover event another div is displayed with two anchor link on which click event are hard coded. Now when anchor is clicked its parent div click also gets fired. I tried to return galse, but it is not working. The code is as below
function onload()
{
$('.cat').css('cursor', 'pointer');
$('.cat').mouseenter(function (e) {
$('<div />', {
'class': 'tip',
html: 'Name: ' + $(this).data('cat-name') + '<br/>Web Name: ' + $(this).data('web-name') + '<br/>Total No. Of SubCategories: ' + $(this).data('total-subcategory') + '<br/><br/>Add Sub Category Edit Category ',
css: {
position: 'fixed',
top: e.pageY,
left: e.pageX,
border: '1px solid red',
background: 'yellow',
padding: '5px',
font: '8'
}
}).appendTo(this);
});
$('.cat').mouseleave(function (e) {
$('.tip', this).remove();
});
$('.cat').on('click', getsubcategory);
}
function getsubcategory()
{
var clicked = $(this).parent().attr('id');
gatsubcategory(clicked);
return false;
}
function editcategory(catid,e) {
alert("Edit " + catid);
return false;
}
function addsubcategory(catid,e) {
alert("Add " + catid);
return false;
}

You need to use event.stopPropagation() to prevents the event from bubbling in child elements click event(which are anchor tag in your case). something like this:
$('.cat a').click(function(e){
e.stopPropagation();
});

You should use event.stopPropagation for that.
It Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
$('.cat').mouseleave(function (e) {
e.stopPropagation();
$('.tip', this).remove();
});
Edit
You can also do it in the inline javascript too, just pass event as another parameter like this,
<a onclick="test(event)"></a>
javascript
function test(event)
{
event.stopPropagation();
}

Related

Conditionally binding/unbinding event listeners

With the help of this post I was able to put together a menu that closes either by toggling a link or clicking outside of it (via mouseup). The problem is that because this mouseup event handler is bound to the document object this is constantly being fired regardless of whether the menu is open or not.
I was wondering how could I conditionally set this handler up only when the menu is visible? I don't necessarily want to invoke: $(document).off("mouseup"); outright in that this toggle is ever fired to initiate the event listener inside $toggleMenu.on("click", function() {...}) via $(document).on("mouseup")
$(function() {
var $toggleMenu = $(".toggle-menu"),
$menu = $(".menu");
$toggleMenu.on("click", function(e) {
e.preventDefault();
toggleUserMenu();
});
$toggleMenu.on("mouseup", function(e) {
e.stopPropagation();
});
$(document).on("mouseup", function (e) {
console.log("Event is still firing");
if (!$menu.is(e.target) && $menu.has(e.target).length === 0) {
$menu.hide();
}
});
function toggleUserMenu() {
var menuIsVisible = $menu.is(":visible");
if (menuIsVisible) {
$menu.hide();
} else {
$menu.show();
}
}
});
.toggle-menu {
color: #444;
display: inline-block;
margin-bottom: 15px;
text-decoration: none;
}
.menu {
border: 1px solid black;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Toggle Menu
<div class="menu">
Menu Item 1
Menu Item 2
Menu Item 3
</div>
I would move your $(document).on("mouseup") code to the toggleUserMenu like this:
function toggleUserMenu() {
var menuIsVisible = $menu.is(":visible");
if (menuIsVisible) {
$menu.hide();
$(document).off("mouseup.my-menu");
} else {
$menu.show();
$(document).on("mouseup.my-menu", function (e) {... });
}
Note, I am using events with namespaces there to avoid cases when $(document).off("mouseup"); will unsubscribe all mouseup handlers.
You could attach the event handler only when the menu is displayed and unattach the event handler when the menu is closed.
So, every time you show the menu, you attach the mouseup handler to allow closing the menu by clicking off menu.
When the menu is closed (by click off menu or by clicking the toggle link), hideMenu hides the menu and unsets the event handler so it won't be called upon further mouseup events.
Note that the mouseup handler is factored out of the .on() code so that .off() is able to reference and remove only that handler--that is to say, if you have other mouseup handlers present, they will remain intact.
http://jsfiddle.net/qmLucq9r/
$(function() {
var $toggleMenu = $(".toggle-menu"),
$menu = $(".menu");
$toggleMenu.on("click", function(e) {
e.preventDefault();
toggleUserMenu();
});
$toggleMenu.on("mouseup", function(e) {
e.stopPropagation();
});
var hideMenu = function() {
$menu.hide();
$(document).off("mouseup", mouseupHandler);
};
var mouseupHandler = function (e) {
console.log("Event is still firing");
if (!$menu.is(e.target) && $menu.has(e.target).length === 0) {
hideMenu();
}
};
function toggleUserMenu() {
var menuIsVisible = $menu.is(":visible");
if (menuIsVisible) {
hideMenu();
} else {
$menu.show();
$(document).on("mouseup", mouseupHandler);
}
}
});

How to prevent click event on anchors when making touch and mouse drag events on its wrapper

How to prevent click event on anchors (redirects to href url, in demo redirecting to google) inside some wrapper when making touch and mouse drag events on this wrapper? With preventDefault and stopPropagation I can only limit bubbling up the DOM, right?
I want to disable links when dragging, and enable click while not dragging.
Here's demo with the problem.
var items = $('#items');
function start(event) {
event.preventDefault();
console.log('touchstart mousedown');
items.on('touchmove mousemove', move);
items.on('touchend mouseup', end);
return false;
}
function move(event) {
console.log('touchmove mousemove');
return false;
}
function end(event) {
console.log('touchend mouseup');
items
.off('touchmove mousemove')
.off('touchend mouseup');
return false;
}
items.on('touchstart mousedown', start);
https://jsfiddle.net/9oxr4quz/4/
I came up with two solutions:
First:
when the mousemove event is triggered, bind a click event and call preventDefault on the event object, to prevent the browser to follow the link. Turn off the jquery click handlers when the touchstart and/or mousedown are triggered.
Javascript:
var items = $('#items a'); // Notice I changed the selector here
function start(event) {
event.preventDefault();
console.log('touchstart mousedown');
items.off('click');
items.on('touchmove mousemove', move);
items.on('touchend mouseup', end);
return false;
}
...
function move(event) {
items.on('click', function(event){ event.preventDefault(); });
console.log('touchmove mousemove');
return false;
}
...
Working demo: http://codepen.io/anon/pen/WvjrPd
Second:
Handle the click events by yourself, that way you can decide when the browser should visit another site and when should do nothing. This can be achieved by replacing the href attribute by a data-link or data-href attribute.
Now, when the touchstart or mousedown events are triggered, turn on the click events; if any of those events lead to a mousemove event, turn off the click events:
HTML:
<div id="items" class="items">
<div class="item">
<a data-link="http://google.com">Anchor</a>
</div>
<div class="item">
<a data-link="http://google.com">Anchor</a>
</div>
</div>
Javascript:
var items = $('#items a'); // Notice I changed the selector here
function start(event) {
event.preventDefault();
console.log('touchstart mousedown');
items.on('click', click); // Turn on click events
items.on('touchmove mousemove', move);
items.on('touchend mouseup', end);
return false;
}
function move(event) {
items.off('click'); // Turn off click events
console.log('touchmove mousemove');
return false;
}
...
function click(event) { // Visit the corresponding link
var link = $(this).attr('data-link');
alert('Visit link: ' + link);
// window.location.href = link;
}
items.on('touchstart mousedown', start);
CSS:
.item {
background-color: gray;
}
.item + .item {
margin-top: 10px;
}
.item a {
cursor: pointer;
display: inline-block;
background-color: blue;
color: white;
padding: 9px;
width: 100%;
height: 100%;
}
Working demo: http://codepen.io/anon/pen/EjmPrJ
What about a CSS approach with JavaScript of using disabling all pointer events when touching or or move then add them back. A quick one is define CSS like this:
a.prevent-me {
pointer-events: none; /* This line */
cursor: default;
}
the using jquery add the class and remove the class like below as needed in your events.
...
$(".item a").addClass("prevent-me");
...
...
$(".item a").removeClass("prevent-me");
...
So the whole solution, I havent tested it might be
var items = $('#items');
function start(event) {
event.preventDefault();
console.log('touchstart mousedown');
$(".item a").addClass("prevent-me"); //remove all click events
items.on('touchmove mousemove', move);
items.on('touchend mouseup', end);
return false;
}
function move(event) {
console.log('touchmove mousemove');
return false;
}
function end(event) {
console.log('touchend mouseup');
items
.off('touchmove mousemove')
.off('touchend mouseup');
$(".item a").removeClass("prevent-me"); //enable back click
return false;
}
items.on('touchstart mousedown', start);

Removing class if click outside of div (targetting class)

I have a menu where user clicks on link and list appears via .addClass( "show-nav" ).
Here is jsFiddle with JS code:
jQuery(".nav-js-trigger").each(function(){
this.onclick = function() {
var hasClass;
hasClass = jQuery(this).next().hasClass( "show-nav" );
jQuery('.show-nav').removeClass('show-nav');
if (hasClass === false) {
jQuery(this).next().addClass( "show-nav" );
}
}
});
I want to remove the class show-nav if the user clicks outside of the div with class show-nav. How do I do this?
I have seen examples of e.target div ID but not class, particularly not a scenario like this.
You can add an listener to the element with an event.stopPropagation() on it, and another listener to the body, to capture this event if not intercepted before.
Something like this:
$(".show-nav").on("click", function(event){
event.stopPropagation();
});
$("body").on("click", function(event){
$(".show-nav").hide(); // or something...
});
To simplify your use-case, here is a JSFiddle.
$(".trigger").on("click", function(event)
{
$(".menu").toggle();
event.stopPropagation();
});
$(".menu").on("click", function(event)
{
event.stopPropagation();
});
$(document).on("click", function(event)
{
$(".menu").hide();
});
.menu
{
display: none;
background: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
menu
<div class="menu">Hello</div>
$(document).on("click", function(e) { if ($(e.target).is(".trigger") === false) {
$(".menu").hide();
}
});

Jquery previous .html() element still showing when new element clicked

I have to write code which finds all anchors and attaches a function that displays a popup of the elements text. My code is probably a mess, but I was able to get it working however the issue I have now is:
If I click link 1, then link 2, then click link 1 again, it displays link 2's text however if i click it again it displays the correct text.
I am not sure exactly how to rewrite or go about fixing this code to properly display the element which is clicked, text all the time.
here is a jsfiddle example: http://jsfiddle.net/2aLfL/1/
$(document).ready(function() {
function deselect(e) {
$('.pop').slideFadeToggle(function() {
e.removeClass('selected');
});
}
$(function() {
$('a').click(function(){
if($(this).hasClass('selected')){
deselect($(this));
} else {
$(this).addClass('selected');
$('.pop').slideFadeToggle();
var elText = $(this).text();
$('#elPop').html("<p>" + "<br><br>" + "You just clicked: <br><b>" + elText + "</b><br><br><br>" + "Click anywhere to Close" + "</p>");
console.log(this);
$("#closeWin").click(function () {
$('.anchorpop').hide();
});
}
return false;
});
});
$(function close(){
$(document).click(function(){
$('.anchorpop').hide();
});
});
$.fn.slideFadeToggle = function(easing, callback) {
return this.animate({ opacity: 'toggle', height: 'toggle' }, 'fast', easing, callback);
};
});
You're binding the following click handler
$("#closeWin").click(function () {
$('.anchorpop').hide();
});
inside <a> click handler so whenever a link is clicked, multiple handlers are being added.
You can avoid many unnecessary code using toggleClass() method.
You can also bind same event handlers to multiple elements by passing additional selectors.
after all your code boils down to
$(function () {
$('a').click(function () {
var htmlString = "<p>" + "<br><br>" + "You just clicked: <br><b>" + $(this).text() + "</b><br><br><br>" + "Click anywhere to Close" + "</p>"
$('.pop').html(htmlString).slideFadeToggle(function () {
$(this).toggleClass('selected');
});
return false;
});
$("#closeWin, .anchorpop").click(function () {
$('.anchorpop').hide();
});
});
and the custome slideFadeToggle function.
Updated Fiddle

document click to hide menu

My document click function isn't hiding my menu when I click the document outside of my menu. When I click the img it shows the menu and when I click the img again it hides it but when I document click I want it to hide the menu does any one know what I'm doing wrong and how to make it work.
var visible = false;
var id = $(this).attr('id');
$(document).not('#' + id + ' div:eq(1)').click(function () {
if (visible) {
$('.dropdownlist .menu').hide();
visible = false;
}
});
$(this).find('div:eq(1)').click(function (e) {
var menu = $(this).parent().find('.menu');
if (!visible) {
menu.show();
visible = true;
} else if (visible) {
menu.hide();
visible = false;
}
menu.css({ 'left': $(this).position().left + $(this).width() - menu.find('ul').width(),
'top': $(this).position().top + $(this).height() });
})
I had a similar problem and solved it with the following code:
$("body").mouseup(function(){
if (visible) {
$('.dropdownlist .menu').hide();
visible = false;
}
});
instead of your $(document).not(.. code.
//add event.stopPropagation() when the user clicks on a .menu element
$('.menu').on('click', function (event) {
//.stopPropagation() will stop the event from bubbling up to the document
event.stopPropagation();
});
//add the click event handler to the image that will open/close .menu elements
$('img').on('click', function (event) {
//we call .stopPropagation() again here so the document won't receive this event
event.stopPropagation();
//cache .menu element
var $div = $('.menu');
//this if statement determines if the .menu should be shown or hidden, in my example I'm animating its top property
if ($div.css('top') == '-50px') {
$div.stop().animate({top : 0}, 250);
} else {
$div.stop().animate({top : '-50px'}, 150);
}
});
//add click event handler to the document to close the .menu
$(document).on('click', function () {
$('div').stop().animate({top : '-50px'}, 150);
});
jsfiddle: http://jsfiddle.net/jasper/n5C9w/1/

Categories