How do I prevent parent event handler on a child node? - javascript

I have a div and it's listend by a event handler:
$('.thediv').click(function() {
$(this).remove()
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="width:500px;height:500px">
<input type="input" style="width:100px;height:20px" />
</div>
The div would be removed if it's clicked.
However, I want to put a text input box on the div and if the user clicks the text input, the div should not be removed. Only when the user clicks the area outside the input box, the div get removed.
What can I do?

Only remove if the target of the event does not match input:
$('.thediv').click(function(e) {
if (!e.target.matches('input')) {
$(this).remove();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="thediv" style="width:500px;height:500px">
other div content
<input style="width:100px;height:20px">
</div>

on input click use .stopPropagation() this will prevent from call the parent click
$('.thediv').click(function(){$(this).remove()});
$('#input').click(function(e) {
e.stopPropagation();
});
<div class="thediv" style="">
<input type="input" id="input" /><br />
text here
<h1>text here </h1>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

In the following demo:
.box is the parent element that listens for the click event.
.box is also referred to as event.currentTarget because it is registered to the click event.
.box is also considered this within the callback function.
The event.target is the origin of the event -- the element that the user clicked.
.box has an <input> child element.
The callback function simply states this:
if the clicked element (aka event.target -- see #4)
is this (aka .box -- see #3), then...
remove this
Note: This will exclude anything within .box that is clicked not just an <input>.
Demo
$('.box').click(function(event) {
if (this === event.target) {
$(this).remove();
}
});
<fieldset class='box' style="width:500px;height:500px">
<input type="text" style="width:100px;height:20px">
</fieldset>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Related

Usage of :not() to filter out elements in event handler

I'm pretty confused by the :not() selector. In plain CSS is seems to be rather straightforward:
section { /* Overriden as expected */
color: red;
}
input {
color: green; /* In effect as expected */
}
:not(input) {
color: blue; /* In effect as expected */
}
<section>
<p>Lorem ipsum</p>
<input value="Lorem ipsum">
</section>
However, when applied to filter the descendants of the selected elements that trigger an event I'm unable to grasp the logic:
jQuery(function($){
$(document).on("keydown", "input", function(event){
// This fires only for <input> as expected
console.log("Event handler #1 on", event.target);
});
$(document).on("keydown", ":not(input)", function(event){
// This fires for *all* elements :-?
console.log("Event handler #2 on", event.target);
// ... even though these checks return the results that intuition suggests
console.log('Is "input"? %s; Is ":not(input)"? %s',
$(event.target).is("input"),
$(event.target).is(":not(input)")
);
});
$(document).on("keydown", "section :not(input)", function(event){
// This *never* fires :-?
console.log("Event handler #3 on", event.target);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section>
<p>Click and type here</p>
<input value="Click and type here">
</section>
What's the rationale behind the way :not() works here?
I'm really looking for an explanation as opposed to a fix.
The issue is that the keydown event bubbles up from the input. If you use :not(input), the handler will not fire when the event was just initialized at the input element, but it will fire when the event bubbles up to the section element. You can check this by checking this inside the function, which will refer to the element to which the event has bubbled when the handler fires. (The event.target will always be the input when you're typing in the input field)
jQuery(function($){
$(document).on("keydown", ":not(input)", function(event){
// This fires for *all* elements :-?
console.log("Event handler #2 on", this);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section>
<p>Click and type here</p>
<input value="Click and type here">
</section>
If you continue adding :nots, you'll see it bubble up all the way up to the HTML tag:
jQuery(function($){
$(document).on("keydown", ":not(input):not(section):not(body)", function(event){
// This fires for *all* elements :-?
console.log("Event handler #2 on", this);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section>
<p>Click and type here</p>
<input value="Click and type here">
</section>
I suppose you could use :not(input):not(section):not(body):not(html), but that's a bit silly and hard to manage.
Your third handler is properly excluding the input from firing the event, but only input (and similar) elements fire keydown events - it can't be fired from a <section>, for example. It might be clearer if there's a textarea child of the section as well as the input - you'll see that the textarea triggers the handler, but the input doesn't:
$(document).on("keydown", "section :not(input)", function(event) {
console.log("Event handler #3 on", event.target);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section>
<p>Click and type here</p>
<input value="Click and type here">
<textarea></textarea>
</section>

How to handle click event in mouse and keyboard?

I have done
some html tags click event it's working by mouse click and
keyboard enter
some html tags click events are are not working when
press in keyboard enter. only working mouse click.
I need both are we excutue in single method
like: Button, Anchor
"Button **and Anchor**" - tags only suporting .
"p,div,span,h1"- tags are not suporting .
Button and Anchor Tag only working both mouse click and keyboard enter
!
remaining element are not working tab using keyboard enter why ?
dont't say keycode method for keyboard enter i need similar button and anchor tag
Here is the demo:
$(document).ready(function(){
$("p").click(function(){
alert("The paragraph was p.");
});
$("div").click(function(){
alert("The paragraph was div.");
});
$("span").click(function(){
alert("The paragraph was span.");
});
$("h1").click(function(){
alert("The paragraph was h1.");
});
$("button").click(function(){
alert("The paragraph was button.");
});
$("a").click(function(){
alert("The paragraph was a.");
});
});
* {
margin-bottom:20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Button and Anchor Tag only working both mouse click and keyboard enter ! </h2>
<h2>remaining element are not working tab using keyboard enter ? </h2>
<br>
<br>
<p tabindex="0">Click on this paragraph.</p>
<div tabindex="0">Click on this div.</div>
<span tabindex="0">Click on this span.</span>
<h1 tabindex="0">Click on this h1.</h1>
<button> Click on this button.</button> <br>
Click on this anchor
Thanks
J.Jayaprakash
You could use the keypress event.
To determine which character was entered, examine the event object that is passed to the handler function. While browsers use differing properties to store this information, jQuery normalizes the .which property so you can reliably use it to retrieve the character code.
function alertTag( tag ){
alert("The element was " + $(tag).prop("tagName"));
}
$(document).ready(function() {
$("p, div, span, h1, button, a").click(function(e) {
alertTag(e.target);
}).keypress(function(e) {
if (e.which == 13) {
e.preventDefault(); // optionally
alertTag(e.target);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p tabindex="0">Click on this paragraph.</p>
<div tabindex="0">Click on this div.</div>
<span tabindex="0">Click on this span.</span>
<h1 tabindex="0">Click on this h1.</h1>
<button> Click on this button.</button> <br>
Click on this anchor
If you want to use the same method for all the elements (while I don't see the point in doing so) you need to include e.preventDefault(). Otherwise, when pressing enter you will trigger both the click and the keypress events.
An alternative could be to force the p, div, span and h1 elements to trigger a click event when pressing enter on them:
$(document).ready(function() {
$("p, div, span, h1, button, a").click(function(e) {
alert("The element was " + $(e.target).prop("tagName"));
});
$("p, div, span, h1").keypress(function(e) {
if (e.which == 13) {
$(e.target).trigger('click');
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p tabindex="0">Click on this paragraph.</p>
<div tabindex="0">Click on this div.</div>
<span tabindex="0">Click on this span.</span>
<h1 tabindex="0">Click on this h1.</h1>
<button> Click on this button.</button> <br>
Click on this anchor
If you really want to do it for all the HTML tags (even when I think that's not a good idea) you can do the following.
$("body *").keypress(function(e) {
if (e.which == 13) {
$(e.target).trigger('click');
}
});
Then, all the elements will react to a enter like they do to a click. But you should really try to replace body * for a selector that covers just the elements that you want. For example, you can add the class .enterTriggersClick to the target elements and then do:
$(".enterTriggersClick").keypress(function(e) { ...

stopPropagation & preventDefault are not working, parent click is still firing

In my code, I have added onclick on parent div and want to perform other action on inner div, but clicking on inner div also triggering parent click.
how to stop that?
$(document).on('click', '.child', function(e) {
e.preventDefault();
e.stopPropagation();
console.log('child');
});
function parentfun(sender) {
console.log('parent');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent" onclick="parentfun(this)">
parent
<div class="child">child</div>
</div>
Above divs are generated on run time on some other event.
Clicking on child, also trigger parent's click. preventDefault & stopPropagation are not working.
FYI: my question is different than How do I prevent a parent's onclick event from firing when a child anchor is clicked?
What you are actually doing here is binding the click-event to the document, not the child-element. So the event has already bubbled up all the way to the document, it's too late to try to stop the bubbling with stopPropagation.
See here when I change the click-handler to the child instead:
$(".child").on('click', function(e) {
e.preventDefault();
e.stopPropagation();
console.log('child');
});
function parentfun(sender) {
console.log('parent');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent" onclick="parentfun(this)">
parent
<div class="child">child</div>
</div>
Edit
As the question changed a bit, here is what you can do (for example) if the elements are created dynamically:
$(document).on('click', '.parent, .child', function(e) {
e.stopPropagation();
if ($(this).is(".child")) {
console.log('child');
} else {
console.log('parent');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
parent
<div class="child">child</div>
</div>
Using plain vanilla JS it works as expected:
function logEventTarget(e) {
e.stopPropagation();
console.log(e.target.id);
}
parentDiv.addEventListener('click', logEventTarget)
childDiv.addEventListener('click', logEventTarget)
<div id="parentDiv">
parent
<div id="childDiv">child</div>
</div>
Using an inline event handler won't pass the event to the handler function:
function logEventTarget(e) {
e.stopPropagation();
console.log(e.target.id);
}
childDiv.addEventListener('click', logEventTarget)
<div id="parentDiv" onclick="logEventTarget()">
parent
<div id="childDiv">child</div>
</div>
One of the many reasons you shouldn't use inline event handlers at all. Note that e.stopPropagation() still works for the childDiv.
You can notice that when clicking the chlid element the parent triggers first (that is why parent prints first then child ) because of event capturing which precedes event bubbling. In-order to stop the event capturing phase from parent you can stop propagating that event and then only child event will trigger.
$(document).on('click', '.child', function(e) {
//e.preventDefault();
e.stopPropagation();
console.log('child');
});
$(document).on('click', '.parent', parentfun);
function parentfun(e) {
e.stopPropagation();
console.log('parent');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
parent
<div class="child">child</div>
</div>
You can also resolve this problem by editing little bit in Your html code
<div class="parent" id="parent-div">
<!-- Just adding parent div text inside span tag -->
<span>parent</span>
<div class="child">child</div>
</div>
now go to jquery code
$('.parent span').on('click',function(){
//only print child text u can do more
alert($('.child').text());
//Change color of child
$('.child').css('color','red');
});

Show div after button click jquery

Hi I try to show a div element in jQuery mobile when the user touch the button. I already created own classes for the button and for the div element, but nothing happens. What classes should I take?
JS:
$(document).ready(function(){
$(".commentbtn").on("click", function(e) {
e.preventDefault(); // in some browsers a button submits if no type=
$(this).siblings("div.comment").toggle();
});
});
CSS:
.comment {
display:none;
}
HTML:
<?php foreach ($result as $key => $row): ?>
<div class="ui-btn-text">
<button class="commentbtn" data-rel="button">comment</button>
<div id="createcomment" class="comment" data-theme="a">
<form data-ajax="false" name="login-form" class="login-form" action="./comments.php" method="post" style="padding:20px 40px;">
<div class="content">
<textarea rows="1" name="text" id="text" class="foo"></textarea>
</div>
</form>
</div>
</div>
<?php endforeach; ?>
You haven't got any element with the class .btn-info so you wouldn't be able to call the event from:
$(".btn-info").on("click", function(e) {
e.preventDefault(); // in some browsers a button submits if no type=
$(this).closest(".comment").children(".comment").show();
});
You have an element with the class .commentbtn which you would then do the same as you did with the .btn-info
$(".commentbtn").on("click", function(e) {
e.preventDefault(); // in some browsers a button submits if no type=
// Console log the element
console.log($(this).closest(".comment").children(".comment"));
// Console log not showing the right element. So you need to get the
// sibling of the clicked button
// Instead of doing - $(this).closest(".comment").children(".comment").show();
// You can do the following
$(this).siblings("div.comment").show();
});
.closest() - looks at the element itself and its parents for a match.
.siblings - Get the siblings of each element in the set of matched elements, optionally filtered by a selector.
Example With .show();
Here an example with .toggle(); If you wanted to show/hide the comment with same button. (Just little extra for you to look at)
Example With .toggle();
UPDATE:
Example with .comment shown on load
Your button has class commentbtn, so you should use that instead of btn-info. Also, you should be looking for the sibling div, not the closest.
$(".commentbtn").on("click", function(e) {
e.preventDefault(); // in some browsers a button submits if no type=
$(this).siblings("div.comment").show();
});
JSFiddle demo

Show/Hide Immediate next element Input

I'm trying to show hide immediate next imput within the div, but it opens all the inputs
I also tried
`$(this).next("input").show();` ( traversing )
nothing seems to work.
Any help?
Here is my http://jsfiddle.net/526stLtg/1/
You need to use siblings() and for toggling visibility use toggle()
$(document).ready(function() {
$(".add-guest > button").click(function() {
$(this).siblings('input').toggle();
});
});
.add-guest input[type="text"] {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="add-guest">
<b>Bride:</b>
<button id="bride">Add</button>
<br>
<input type="text" name="Bride">
</div>
<br/>
<br/>
<div class="add-guest">
<b>Groom:</b>
<button id="bride">Add</button>
<br>
<input type="text" name="Bride">
</div>
You can use this to refer to html element and using .parent() and .find():
$(document).ready(function() {
$(".add-guest > button").click(function() {
$(this).text() === "Add" ? $(this).text("Remove") : $(this).text("Add");
$(this).parent().find("input").toggle();
});
});
.add-guest input[type="text"] {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="add-guest">
<b>Bride:</b>
<button id="bride">Add</button>
<br>
<input type="text" name="Bride">
</div>
<br/>
<br/>
<div class="add-guest">
<b>Groom:</b>
<button id="bride">Add</button>
<br>
<input type="text" name="Bride">
</div>
Additionally you can use .toggle() instead of .show.
You can use $(this) to select the clicked button (the event trigger).
Then, if you look at your code, you'll see that the next element is a <br/>, and the next the <input> that you want to show. So, if you change:
$(".add-guest > input").show();
to
$(this).next().next().show();
It will work. You can think tha you can also use a selector to find the first sibling filtered by the selector, i.e.
$(this).next('input').show();
But this doesn't work. This checks if the sibling can be selected with the paseed selector. But you can use the .nextAll('input'), only because in this case there are only one sibling which can be seelcted like this. If not you could use this selector, and .first()
Your original code was selecting all inputs precede by elements with the .add-guest class, whic is not what you wanted to do.
If there are multiple input elemnts within div and you want to select first input element only then use :first pseudo-class
$(this).parent().find("input:first").toggle();

Categories