I have a javascript that opens up a hidden div:
<script>
function dropdown()
{ document.getElementById("login_dropdown").style.display="block"; }
</script>
The html is:
<div onclick="dropdown()">
<div id="login_dropdown">STUFF</div>
</div>
The CSS is:
<style>
#login_dropdown {
width: 150px;
display:none;
}</style>
Using javascript alone, how can I hide this div when I click anywhere else on the page, excluding the opened DIV itself.
Something like this with vanilljs
document.addEventListener('click', function(event){
const yourContainer = document.querySelector('....');
if(!yourContainer.contains(event.target)) {
//hide things classes.. yourContainer.classList.add('hidden');
}
});
You could do this
var elem = document.getElementById("login_dropdown");
(document.body || document.documentElement).addEventListener('click', function (event) {
// If the element on which the click event occurs is not the dropdown, then hide it
if (event.target !== elem)
elem.style.display="none";
}, false);
function closest(e, t){
return !e? false : e === t ? true : closest(e.parentNode, t);
}
container = document.getElementById("popup");
open = document.getElementById("open");
open.addEventListener("click", function(e) {
container.style.display = "block";
open.disabled = true;
e.stopPropagation();
});
document.body.addEventListener("click", function(e) {
if (!closest(e.target, container)) {
container.style.display = "none";
open.disabled = false;
}
});
#popup {
border: 1px solid #ccc;
padding: 5px;
display: none;
width: 200px;
}
<div id="container">
<button id="open">open</button>
<div id="popup">PopUp</div>
</div>
Something like this:
$("document").mouseup(function(e)
{
var subject = $("#login_dropdown");
if(e.target.id != subject.attr('id'))
{
subject.css('display', 'none');
}
});
works like this. When you click anywhere on the page, the handler fires and compares the ID of the open tab vs the id of the document (which there is none) - so it closes the tab. However, if you click the tab, the handler fires, checks the ID, sees the target is the same and fails the test (thus not closing the tab).
Related
I created a side menu, which displays and hides when clicking the menu button. Now, I would like that the menu closes when I click outside the menu, but I cannot figure out how to do it.
I have tried adding a clicklistener to the body, but this disables the menu completely. I also thougt about getting the ID of the clicked element anywhere in the body and close the menu if clickedElement != sideBar && sideBar.style = "200px", but I cannot get it to work. Can someone help me out here? I would like to find a solution without JQuery.
menuBtn.addEventListener("click", function () {
if (sideBar.style.width == "200px") {
sideBar.style.width = "0px";
setTimeout(function () {
menuItems.style.display = "none";
}, 1000);
} else {
sideBar.style.width = "200px";
menuItems.style.display = "block";
}
});
You can add an event listener to the parent container and check if the click's target is inside the element or not, something like:
document.addEventListener("click", (e) => {
if (box.contains(e.target)) {
result.innerHTML = "inside";
} else {
result.innerHTML = "outside";
}
});
#box {
width: 100px;
height: 100px;
background-color: dodgerblue;
}
<div id="box"></div>
<div id="result"></div>
I'm trying to catch a click event on an element which changes its z-pos using appendchild on the mousedown event. The problem is that when you click an element when its not the front element then the click event doesn't fire. I know this is because it is removed from the DOM and then re-added but I'm not sure how I could fix it so that the click also fire when the element is moved to the front.
MyObject = {
init(parent, text) {
this.parent = parent;
this.text= text;
this.visual = document.createElement("div");
this.visual.setAttribute("class", "object");
this.visual.appendChild(document.createTextNode(text))
parent.appendChild(this.visual);;
this.visual.addEventListener("click", (e) => { this.onClicked(e); });
this.visual.addEventListener("mousedown", (e) => { this.onMouseDown (e); });
},
toTop() {
this.parent.appendChild(this.visual);
},
onClicked(e) {
alert(this.text + " was clicked");
e.stopPropagation();
},
onMouseDown(e) {
this.toTop();
// I'm also doing other things here
}
};
var parent = document.querySelector(".parent");
parent.addEventListener("click", (e) => { alert("parent clicked"); });
var createObj = function(text) {
var obj = Object.create(MyObject);
obj.init (parent, text);
};
createObj ("object 1");
createObj ("object 2");
createObj ("object 3");
createObj ("object 4");
.parent {
border: 1px solid red;
}
.object {
background: #0F0;
border: 1px solid black;
margin: 8px;
}
<div class="parent">
</div>
So in this example you always have to click the bottom element to get the alert while I would also like to get the alert when an other items is pressed.
edit: I'm testing in chrome (55.0.2883.87) and the code might not work in other browsers.
I have a div as follows
<div class="parent">
<!--several child divs now-->
</div>
Now, I have registered a click handler on body using AngularJS as follows:
HTML:
<body ng-click="registerClick($event)">
</body>
Controller:
$scope.registerClick(e) {
//Here check if the parent div or one of its children were clicked
}
How, can use $event in my handler to determine if the div with class 'parent' or one of its children were clicked?
Change it to this:
$scope.registerClick(e) {
if (e.target.classList.contains('parent')){
// The .parent div is clicked
} else if (e.target.parentNode.classList.contains('parent')){
// Some child of the .parent div is clicked
} else {
var elem = e.target;
while(elem.tagName != 'body' || !elem.classList.contains('parent')){
elem = elem.parentNode;
}
if (elem.classList.contains('parent')){
console.log('DIV .parent')
} else {
console.log('Body tag reached. No .parent element found');
}
}
}
e.target is the clicked element. Use it to determine which element was clicked. This is a clean JavaScript solution. You wont even need the $scope.registerClick(e) { part if can attach the event like so:
someDiv.onclick = function(){/* Same code as above. */}
if you use the latter approach, 'this' points to the div, so you can that the validations a little bit.
You can do something like
var app = angular.module('my-app', [], function() {})
app.controller('AppController', function($scope) {
$scope.registerClick = function($event) {
//if has jQuery
if ($($event.target).closest('.parent').length) {
console.log('clicked parent');
$scope.jQuery = true;
} else {
$scope.jQuery = false;
}
var isParent = false;
if (angular.isFunction($event.target.closest)) {
isParent = !!$event.target.closest('.parent');
} else {
var tmp = $event.target;
do {
isParent = tmp.classList.contains('parent');
tmp = tmp.parentNode;
} while (tmp && tmp.classList && !isParent);
}
$scope.native = isParent;
};
})
.parent {
border: 1px solid grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="my-app">
<div ng-controller="AppController" ng-click="registerClick($event)">
<div>outside</div>
<div class="parent">
parent
<div>div</div>
<div>div</div>
</div>
<div>
jQuery: {{jQuery}}
</div>
<div>
native: {{native}}
</div>
</div>
</div>
How can I remove an attribute of an element on click outside or on another div of same type? Here's my code:
HTML:
<div id="container">
<div data-something></div>
<div data-something></div>
</div>
JavaScript:
var elements = document.querySelectorAll("[data-something]");
Array.prototype.forEach.call(elements, function(element) {
// Adding
element.onclick = function() {
this.setAttribute("data-adding", "");
};
// Removing -- Example
element.onclickoutside = function() {
this.removeAttribute("data-adding");
};
});
I would probably use a click handler on the document, and then remove the attribute from any element that had it that wasn't in the bubbling path.
document.addEventListener("click", function(e) {
Array.prototype.forEach.call(document.querySelectorAll("*[data-adding][data-something]"), function(element) {
var node, found = false;
for (node = e.target; !found && node; node = node.parentNode) {
if (node === element) {
found = true;
}
}
if (!found) {
element.removeAttribute("data-adding");
}
});
}, false);
...or something along those lines.
Live Example:
document.addEventListener("click", function(e) {
Array.prototype.forEach.call(document.querySelectorAll("*[data-adding]"), function(element) {
var node, found = false;
for (node = e.target; !found && node; node = node.parentNode) {
if (node === element) {
found = true;
}
}
if (!found) {
element.removeAttribute("data-adding");
}
});
}, false);
*[data-adding] {
color: red;
}
<div data-adding data-something>One</div>
<div data-adding data-something>Two</div>
You can use Node.contains() inside a global click event handler to check if a click is outside an element, and handle the event appropriately:
box = document.getElementById('box');
lastEvent = document.getElementById('event');
box.addEventListener('click', function(event) {
// click inside box
// (do stuff here...)
lastEvent.textContent = 'Inside';
});
window.addEventListener('click', function(event) {
if (!box.contains(event.target)) {
// click outside box
// (do stuff here...)
lastEvent.textContent = 'Outside';
}
});
#box {
width: 200px;
height: 50px;
background-color: #ffaaaa;
}
<div id="box">Click inside or outside me</div>
<div>Last event: <span id="event">(none)</span>
</div>
I want to make popup div that disappears when i click outside of it. I need pure js, not a jQuery or something.
So i do the following...
function that make div to dissapear:
function closePopUps(){
if(document.getElementById('contact-details-div'))
document.getElementById('contact-details-div').style.display = 'none';
//...same code further...
}
function closePopUpsBody(e){
//finding current target - http://www.quirksmode.org/js/events_properties.html#target
var targ;
if (!e) var e = window.event;
if (e.target) targ = e.target;
else if (e.srcElement) targ = e.srcElement;
if (targ.nodeType == 3) // defeat Safari bug
targ = targ.parentNode;
//is we inside div?
while (targ.parentNode) {
//filtering "Close" button inside div
if (targ.className && targ.className == 'closebtn')
break;
if (targ.className && targ.className == 'contact-profile-popup')
break;
targ = targ.parentNode;
}
//if it not a div, or close button, hide all divs and remove event handler
if ((targ.className && targ.className == 'closebtn')
|| !(targ.className && targ.className == 'contact-profile-popup')) {
if(document.getElementById('contact-details-div'))
document.getElementById('contact-details-div').style.display = 'none';
//...some more code here...
document.body.onclick = null;
}
}
maybe this code is ugly, but this not a main problem...
main problem is when i attach an event to body, it executes immediately! and div dissapears immediately, i even don't see it.
<tr onclick="
closePopUps();
document.getElementById('contact-details-div').style.display='block';
document.body.onclick = closePopUpsBody;
return false;">
i though if i don't use parentheses, it will not executes?
document.body.onclick = closePopUpsBody(); //this executes
document.body.onclick = function(){closePopUpsBody()}; //this is not
document.body.onclick = closePopUpsBody; //this is not
finally i finished with this decision
<tr onclick="
closePopUps();
document.getElementById('contact-details-div').style.display='block';
setTimeout('document.body.onclick = closePopUpsBody;', 500);
return false;">
but i think this is madness. so, what i am doing wrong?
You should stop event bubbling. Simple [demo]
var box = document.getElementById('box');
var close = document.getElementById('close');
// click on a box does nothing
box.onclick = function (e) {
e = e || window.event;
e.cancelBubble = true;
if (e.stopPropagation)
e.stopPropagation();
}
// click everywhere else closes the box
function close_box() {
if (box) box.style.display = "none";
}
close.onclick = document.onclick = close_box;
Usually events are propagated to the parents. If you click on a <div>, then <body> also will have its onClick called.
The first thing is: debug the order of called functions: place window.dump("I am called!") kind of things in your handlers.
I suppose you need to call event.stopPropagation() somewhere in your code. (See https://developer.mozilla.org/en/DOM/event )
About the parentheses question:
document.body.onclick = closePopUpsBody;//this is not
document.body.onclick = closePopUpsBody();//this executes
This executes, because you are calling a function closePopUpsBody() to return a value which will be assigned to the onclick property. In JavaScript the function name represents the function object (as any other variable). If you place parentheses after a variable name, then you say: 'execute it for me, as a function`.
Here 's a full example of how you could accomplish that.
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title></title>
<style>
body { font-family: Tahoma; font-size: 1.1em; background: #666666; color: White; }
#layer01 { border: 1px solid black; width: 200px; height: 100px; position: absolute;
top: 100px; left: 100px; background: white; padding: 10px; color: Black;
display: block; }
</style>
</head>
<body>
Click anywhere outside the layer to hide it.
<div id="layer01"> Test Layer </div>
<script type="text/javascript">
isIE = (window.ActiveXObject) ? true : false;
document.onclick = function (e) {
var l = document.getElementById("layer01");
if (!isIE && e.originalTarget == l)
e.stopPropagation();
else if (isIE && event.srcElement == l)
event.cancelBubble = true;
else
l.style.display = "none";
}
</script>
</body>
</html>