I have some dynamically created divs . And when the user clicks on the screen I want to check if it was on one of the dynamically created divs.But it doesnt seem to work. I already have a window.addeventListener but that too is not working for the dynamically created divs.
var divk = document.createElement("div");
divk.className="divk";
window.addEventListener('click', function(e){
if (document.getElementById('outside_click_purpose').contains(e.target)){
currentItem = e.target;
if (currentItem.classList.contains("divk")) {
alert("contains !!!");
}
}
});
I think you need to use event delegation then use matches
Notice how we use
e.target.matches('.dynamic')
To check for the presence of our class, we can use any valid css selector
For example, if we wanted to ensure it was a div:
e.target.matches('div.dynamic');
See the demonstration below:
// Add some dynamic divs
const getDiv = (content) => {
const div = document.createElement('div');
div.className = 'dynamic';
div.innerHTML = content;
return div;
};
const setMessage = (msg) => document.querySelector('.clicked').innerText = msg;
document.addEventListener('DOMContentLoaded', () => {
const container = document.querySelector('#container');
for(let i = 0; i< 10; i++) {
container.appendChild(getDiv(`Dynamic ${i}`));
}
});
// Use event delegation
document.addEventListener('click', (e) => {
if(e.target.matches('.dynamic')) {
setMessage(`Clicked a dynamic div - text ${e.target.innerText}`);
}
else {
setMessage('Click was not on dynamic');
}
});
.clicked {
height: 20px;
border: 1px solid red;
}
.manual {
background-color: blue;
color: white;
}
<div class="clicked"></div>
<div class="manual">Manual</div>
<div class="manual">Manual</div>
<div id="container"></div>
Related
I have a list of ids, when one of them is clicked I want to give it the attribute .className="open.
So far what I've done is to put all ids in a list and try to loop through them.
const memberB = document.querySelectorAll('#memberA, #memberAA, #memberAAA ');
for (var i = 0; i < memberB.length; i++) {
memberB[i].onclick = function(){
alert(memberB[i])
if(memberB[i].className=="open"){
memberB[i].className="";
}
else{
memberB[i].className="open";
}
}
What did I do wrong, I try to alert to see if I get the element that i clicked, all i get is 'undefined'.
you can use forEach to loop the NodeList which use querySelectorAll method, and use addEventListener to watch click event happen on all the elements you selected. Finally, use Element.classList.toggle method to toggle the class open or close
there is an example of toggle its background color after click
const members = document.querySelectorAll('.member');
members.forEach(member => {
member.addEventListener('click', e => {
e.target.classList.toggle('hight-light');
});
});
.member {
background-color: gray;
}
.hight-light {
background-color: green;
}
<div class="container">
<div class="member">1</div>
<div class="member hight-light">2</div>
<div class="member">3</div>
<div class="member">4</div>
</div>
I have a code snippet I like to keep around to do these kind of things in a single event listener
window.addEvent = (event_type, target, callback) => {
document.addEventListener(event_type, function (event) {
// If the event doesn't have a target
// Or the target doesn't look like a DOM element (no matches method
// Bail from the listener
if (event.target && typeof (event.target.matches) === 'function') {
if (!event.target.matches(target)) {
// If the element triggering the event is contained in the selector
// Copy the event and trigger it on the right target (keep original in case)
if (event.target.closest(target)) {
const new_event = new CustomEvent(event.type, event);
new_event.data = { originalTarget: event.target };
event.target.closest(target).dispatchEvent(new_event);
}
} else {
callback(event);
}
}
});
};
then in your case I'd do this
window.addEvent('click', '#memberA,#memberAA,#memberAAA', (event) => {
event.target.classList.toggle('open');
});
The script runs befor the DOM elements load.
You can put the script as a function inside an $(document).ready such that it runs after all the elements have been loaded.
$(document).ready(
function () {
const memberB = document.querySelectorAll('#memberA, #memberAA, #memberAAA ');
for (let i = 0; i < memberB.length; i++) {
memberB[i].onclick = function () {
//alert(memberB[i])
if (memberB[i].className === "open") {
memberB[i].className = "";
} else {
memberB[i].className = "open";
}
alert(memberB[i].className)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="memberA">A</button>
<button id="memberAA">AA</button>
<button id="memberAAA">AAA</button>
Let me know if this works!
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 wrote this little script to change a class color on click, it works, but i would to restore the primary color with a second click.
function changeColor1() {
document.getElementById("ip-custom").className = "red";
}
function init() {
document.getElementById("ip-custom").onclick = changeColor1;
}
window.onload = init();
.red {
color: #f00;
}
<button id="ip-custom">Example</button>
You can toggle class red like following.
function changeColor1() {
document.getElementById("ip-custom").classList.toggle('red');
}
Full snippet
function changeColor1() {
document.getElementById("ip-custom").classList.toggle('red');
}
function init() {
document.getElementById("ip-custom").onclick = changeColor1;
}
window.onload = init();
.red {
color: #f00;
}
<button id="ip-custom">Example</button>
If you want to use plain js use the classList.toggle function:
function changeColor1() {
document.getElementById("ip-custom").classList.toggle('red');
}
If you use jQuery you can use the toggleClass function:
function changeColor1() {
$("#ip-custom").toggleClass("red");
}
classList documentation
toggleClass documentation
Since you have included the tag jquery, I'll provide an answer using that and plain old javascript.
JavaScript
Check for the existence of the class to determine if you should then add or remove it.
function changeColor1() {
if (document.getElementById("ip-custom").className == "red")
document.getElementById("ip-custom").className = "";
else
document.getElementById("ip-custom").className = "red";
}
function init() {
document.getElementById("ip-custom").onclick = changeColor1;
}
window.onload = init();
.red {
color: #f00;
}
<button id="ip-custom">Example</button>
jQuery
You can make use of jQuery's toggleClass() method.
Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the state argument.
$(function() {
$('#ip-custom').on('click', function() {
$(this).toggleClass('red');
});
});
.red {
color: #f00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="ip-custom">Example</button>
This solutions only works in your case, when element has no class.
So, it add red class o remove all clasess;
function toggleClassRed() {
var element = document.getElementById("ip-custom"),
clazz = element.className || '';
element.className = clazz === '' ? 'red' : '';
}
function init() {
document.getElementById("ip-custom").onclick = toggleClassRed;
}
window.onload = init();
.red {
color: #f00;
}
<button id="ip-custom">Example</button>
You have a simple solution to save the state in a variable.
var clicked = false;
function changeColor1() {
if(!clicked){
document.getElementById("ip-custom").className = "red";
clicked = true;
}else{
document.getElementById("ip-custom").className = "";
clicked = false;
}
}
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>