On Drop target enter and leave custom event - javascript

I have one drop target div which have some nested div's, i add dragover event to parent div and add 'drag-allow' attrib to nested divs. I want to add custom event fires when mouse enters or leave any child div.
<div id="container">
<div id="page1" drag-allow >
Page #1
</div>
<div id="page2" drag-allow>
Page #2
</div>
<div id="page3" drag-allow>
Page #3
</div>
var ground = document.getElementById('container');
...
ground.addEventListener('dragover', function(e){
evt.preventDefault();
evt.stopPropagation();
evt.target.id; // custom event will fire based on child div's id
}, false);

You need to add two more events like
ground.addEventListener('dragenter', function(e){
if(e.target.nodeType == Node.ELEMENT_NODE && e.target.hasAttribute('drag-allow')){
// this will check drop area is div and must have attribute drag-allow
console.log(e.target);
}
}, false);
ground.addEventListener('dragleave', function(e){
// on leave event fires on every nested div like above event
}, false);

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>

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');
});

Track all elements on page

I'm attempting to track events for all UI elements on a page. The page contains dynamically generated content and various frameworks / libraries. Initially I tracked elements through creating a css class "track" , then adding style "track" to tracked elements. elements are then tracked using :
$('.track').on('click', function() {
console.log('Div clicked' + this.id);
console.log(window.location.href);
console.log(new Date().getTime());
});
As content can be dynamically generated I wanted a method to track these elements also. So tried this using wildcard jQuery operator.
In this fiddle : https://jsfiddle.net/xx68trhg/37/ I'm attempting to track all elements using the jquery '*' selector.
Using jQuery '*' selector appears to fire the event for all elements of given type.
So for this case if is clicked all the click event is fired for all divs. But id is just available for div being clicked.
For the th element the click event is fired twice , what is reason for this ?
Can the source be modified that event is fired for just currently selected event ?
fiddle src :
$(document).ready(function() {
$('*').each(function(i, ele) {
$(this).addClass("tracked");
});
$('.tracked').on('click', function() {
console.log('Div clicked' + this.id);
console.log(window.location.href);
console.log(new Date().getTime());
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<!-- <div id="1" data-track="thisdiv">
Any clicks in here should be tracked
</div>
-->
<div id="1">
Any clicks in here should be tracked 1
</div>
<div id="2">
Any clicks in here should be tracked 2
</div>
<div id="3">
Any clicks in here should be tracked 3
</div>
<th id="th">tester</th>
You can try with:
$(document).ready(function() {
$("body > *").click(function(event) {
console.log(event.target.id);
});
});
$(document).ready(function() {
$("body > *").click(function(event) {
console.log(event.target.id);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="1">
Any clicks in here should be tracked 1
</div>
<div id="2">
Any clicks in here should be tracked 2
</div>
<div id="3">
Any clicks in here should be tracked 3
</div>
<table>
<tr>
<td>Cols 1</td>
<td id="td">Cols 2</td>
</tr>
</table>
<p id="th">tester</p>
You may want to use event delegation to target the elements you need. Advantage is that this also works for dynamically generated elements. See code for an example of this.
// method to add/set data-attribute and value
const nClicksInit = (element, n = "0") => element.setAttribute("data-nclicked", n);
// add data-attribute to all current divs (see css for usage)
// btw: we can't use the method directly (forEach(nClicksInit))
// because that would send the forEach iterator as the value of parameter n
document.querySelectorAll("div").forEach(elem => nClicksInit(elem));
// add a click handler to the document body. You only need one handler method
// (clickHandling) to handle all click events
document.querySelector('body').addEventListener('click', clickHandling);
function clickHandling(evt) {
// evt.target is the element the event is generated
// from. Now, let's detect what was clicked. If none of the
// conditions hereafter are met, this method does nothing.
const from = evt.target;
if (/^div$/i.test(from.nodeName)) {
// aha, it's a div, let's increment the number of detected
// clicks in data-attribute
nClicksInit(from, +from.getAttribute("data-nclicked") + 1);
}
if (from.id === "addDiv") {
// allright, it's button#addDiv, so add a div element
let newElement = document.createElement("div");
newElement.innerHTML = "My clicks are also tracked ;)";
const otherDivs = document.querySelectorAll("div");
otherDivs[otherDivs.length-1].after(newElement);
nClicksInit(newElement);
}
}
body {
font: 12px/15px normal verdana, arial;
margin: 2em;
}
div {
cursor:pointer;
}
div:hover {
color: red;
}
div:hover:before {
content: '['attr(data-nclicked)' click(s) detected] ';
color: green;
}
#addDiv:hover:after {
content: " and see what happens";
}
<div id="1">
Click me and see if clicks are tracked
</div>
<div id="2">
Click me and see if clicks are tracked
</div>
<div id="3">
Click me and see if clicks are tracked
</div>
<p>
<button id="addDiv">Add a div</button>
</p>
<h3 id="th">No events are tracked here, so clicking doesn't do anything</h3>
You can invoke the stopPropagation and the condition this === e.currentTarget to ensure invoke the handler function of the event source DOM.
And you must know the <th> tag must wrapped by <table>, otherwise it will not be rendered.
$(document).ready(function() {
$('*').each(function(i, ele) {
$(this).addClass("tracked");
});
$('.tracked').on('click', function(e) {
if (this === e.currentTarget) {
e.stopPropagation();
console.log('Div clicked' + this.id);
console.log(window.location.href);
console.log(new Date().getTime());
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<!-- <div id="1" data-track="thisdiv">
Any clicks in here should be tracked
</div>
-->
<div id="1">
Any clicks in here should be tracked 1
</div>
<div id="2">
Any clicks in here should be tracked 2
</div>
<div id="3">
Any clicks in here should be tracked 3
</div>
<table>
<th id="th">tester</th>
</table>

Hide all elements except one, And show all elements again

<body>
<div id="e1">Element X1</div>
<div id="e2">Element 2X</div>
<div id="e3">Element X3</div>
Hide
</body>
How can i hide the entire body And only show #e2 when i click on #hide, But if i clicked anywhere else out of #e2 again, the hide effect will stop and return to normal.
Something like this? NB: make sure to give your hide link a unique ID.
Showing/hiding works well with jQuery show and hide methods, but since you wanted the elements to stay in their place, it is more suitable to use the visibility style attribute:
$('#hide').click(function () {
// hide all in body except #e2, and #e2's parents.
$('body *').not($('#e2').parents().addBack()).css({visibility: 'hidden'});
return false; // cancel bubbling and default hyperlink effect.
});
$('#e2').click(function () { // click on #e2
return false; // cancel bubbling -- ignore click.
})
$(document).click(function (e) { // click on document
$('body *').css({visibility: 'visible'}); // show all in body.
});
div { border: 1px solid}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="e1">Element X1</div>
<div id="e2">Element 2X</div>
<div id="e3">Element X3</div>
Hide
Be aware that these div elements stretch across horizontally, so a click to the right of the text "Element 2X" will still be on #e2.
Something like this:
// Get reference to the hyperlink
var hideElem = document.getElementById("e4");
// Set up click event handler for link
hideElem.addEventListener("click", function(e){
var elems = document.querySelectorAll("body *:not(#e2)");
Array.prototype.slice.call(elems).forEach(function(value){
value.classList.add("hide");
});
e.stopPropagation();
});
// Set up click event handler for document
document.addEventListener("click", function(){
var elems = document.querySelectorAll("body *");
Array.prototype.slice.call(elems).forEach(function(value){
value.classList.remove("hide");
});
});
.hide { display:none; }
<div id="e1">Element X1</div>
<div id="e2">Element 2X</div>
<div id="e3">Element X3</div>
Hide
$('body').click(function(evt){
if(!$(evt.target).is('#e2')) {
//If not e2 is clicked then restore the state back of page by removing a specific class
}
});
You will need help of css class .hide {display:none;} and add and remove this class when e2 is clicked and remove this class when body is clicked but not e2 as provided above

How to bind click event to element hasn't specific child using jquery?

I have several elements on a page like bottom code.
<div>
click
some content
</div>
They can be clicked and jQuery picks that click. However one of the elements has a a link that is clicked should not be picked as a click of the parent element.
$('div:not(#notme)').on('click', function(e) {
// do something
});
Doesn't seem to work for some reason...
Use :has selector to selecting div element has specific child. In :has use :not.
$("div:has(a:not(#notme))").on("click", function(e) {
console.log("clicked");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
click
some content
</div>
<div>
<a href="#" >click2</a>
some content 2
</div>
You may try:
$('div').on('click', function(e) {
if($(e.target).attr("id") !== "notme") {
// do something
}
});
$('#notme').on('click', function(e) {
e.stopPropagation();
});

Categories