How to prevent child element executing onmousedown event - javascript

I've got the following markup on the page
<div id="box">
<div id="box_child_one"></div>
<div id="box_child_two"></div>
<div id="box_child_three"></div>
</div>
I need to trigger the onmousedown event on all elements inside the #box div so i've got this javascript code:
var element = "#box";
document.querySelector(element).onmousedown = function() {
alert("triggered");
};
However, I do not want onmousedown being triggered on the #box_child_three element.
How can I achieve this?
Thank you.

Check event.target to find out which element was actually clicked on.
var element = "#box";
document.querySelector(element).onmousedown = function(e) {
if (e.target.id !== "box_child_three") {
alert("triggered");
}
};
<div id="box">
<div id="box_child_one">one</div>
<div id="box_child_two">two</div>
<div id="box_child_three">three</div>
</div>

You need to stopPropagation for the event when element three is clicked so that it doesn't bubble up to the parent (box) element.
document.getElementById('box').addEventListener('click', () =>
alert('triggered')
);
document.getElementById('box_child_three').addEventListener('click', e =>
e.stopPropagation()
);
<div id="box">
<div id="box_child_one">one</div>
<div id="box_child_two">two</div>
<div id="box_child_three">three</div>
</div>

<div id="box">
<div id="box_child_one" trigger></div>
<div id="box_child_two" trigger></div>
<div id="box_child_three"></div>
</div>
<script>
document.querySelector('#box').onclick = function(e){
if(e.target.hasAttribute('trigger')){
alert('event fired')
}
}
</script>
I'd go for this. As you are now no longer relying on an id to carry this out making it more re-usable

Related

How to add event listeners to div elements?

I want to add an event listener to each of the div elements with the class "box" here:
<div class="gameBox">
<div class="msgs">
<p class="msg">Click in a box to play. Crosses start.</p>
</div>
<div class="gameTable">
<div class="box" id="0"></div>
<div class="box" id="1"></div>
<div class="box" id="2"></div>
<div class="box" id="3"></div>
<div class="box" id="4"></div>
<div class="box" id="5"></div>
<div class="box" id="6"></div>
<div class="box" id="7"></div>
<div class="box" id="8"></div>
</div>
<div class="reset">Reset</div>
</div>
let elementsArray = document.querySelectorAll(".box");
elementsArray.forEach(function(div) {
div.addEventListener("click", function() {
alert("AA");
});
});
This is the JavaScript I have used to do this, however it does not return anything. I think the issue may be that the div element is inside another div element because the code works when I take it out of the rest of my program. Please teach me the path to redemtion.
It looks like your code is correct. One thing you can try is to make sure that the script is being executed after the elements are added to the page. You can do this by placing your script at the end of the <body> element, just before the closing </body> tag.
Here's an example:
<body>
...
<div class="gameBox">
...
</div>
<script>
let elementsArray = document.querySelectorAll(".box");
elementsArray.forEach(function(div) {
div.addEventListener("click", function() {
alert("AA");
});
});
</script>
</body>
This ensures that the elements with the box class are added to the page before your script runs.
Another thing you can try is to add a debug statement to your code to see if the elementsArray variable is actually getting populated with the elements you expect. You can do this by adding a console.log statement, like this:
let elementsArray = document.querySelectorAll(".box");
console.log(elementsArray);
elementsArray.forEach(function(div) {
div.addEventListener("click", function() {
alert("AA");
});
});
This will print the elementsArray variable to the JavaScript console, which you can access in your web browser. This will allow you to verify that the elementsArray variable contains the elements you expect.
One solution is to add an event listener to the window object instead, and check if the clicked element is one of these .box elements.
window.addEventListener("click", (e) => {
if (e.target.classList.contains("box")) {
console.log(e.target.id);
}
});

Javascript optimization: repetition of a same function

I want to use a getElemendbyId function several times, just by passing the name of the ID as a variable.
I guess there is a more elegant way to do it than:
<div id="1" onclick="myFunction2()"></div>
<div id="2" onclick="myFunction3()"></div>
<div id="3" onclick="myFunction4()"></div>
<div id="4" onclick="myFunction5()"></div>
<script>
function myFunction2() { document.getElementById("2").innerHTML = "test2"; }
function myFunction3() { document.getElementById("3").innerHTML = "test3"; }
function myFunction4() { document.getElementById("4").innerHTML = "test4"; }
</script>
Thanks!
<div id="1" onclick="myFunction(2, 'test2')"></div>
<div id="2" onclick="myFunction(3, 'test3')"></div>
<div id="3" onclick="myFunction(4, 'test4')"></div>
<div id="4" onclick="myFunction(5, 'test5')"></div>
<script>
function myFunction(id, content) {
document.getElementById(id).innerHTML = content;
}
</script>
There are a couple of ways to go about this, but in all scenarios you really should not use inline event handling attributes (onclick). There are many reasons not to use this 20+ year old technique that just will not die the death it deserved to almost 10 years ago. Additionally, don't use .innerHTML to get/set values that don't contain any HTML as it is wasteful, in terms of performance and it opens up security holes in your application. Instead, use .textContent to get/set non-HTML values.
For each element to have its own handler:
Get all the elements that need a similar handler into an array
Loop over the array
Assign a handler to the current array element
// Get all the elements that need the same handler into an Array
let divs = Array.prototype.slice.call(document.querySelectorAll("div"));
// Iterate the array
divs.forEach(function(div){
// Set up the handler
div.addEventListener("click", function(){
div.textContent = "test" + div.id;
});
});
<div id="1">click me</div>
<div id="2">click me</div>
<div id="3">click me</div>
<div id="4">click me</div>
To set up just one handler and use event delegation:
Assign a common handler to an ancestor of all the elements in question
In the handler, act upon the specific element that triggered the event.
// Set up an event handler on the container element
document.querySelector(".parent").addEventListener("click", function(event){
// Act upon the target of the event (the element that triggered the
// event in the first place).
event.target.textContent = "test" + event.target.id;
});
<div class="parent">
<div id="1">click me</div>
<div id="2">click me</div>
<div id="3">click me</div>
<div id="4">click me</div>
</div>
A more elegant solution than inline on<...> event handlers is to call addEventListener on the parent element (read about event delegation here). Once the listener is registered you can use the event argument to determine what target the user has clicked and what action to be taken, if any.
For example, in the scenario below we evaluate the event to determine if one of our <div> elements were clicked - if so, call myFunction with the appropriate data passed in:
document.addEventListener('click', handleClick)
function handleClick(event) {
if (event.target.tagName === 'DIV') {
myFunction(event.target);
}
}
function myFunction(el) {
el.innerHTML = `test${el.id}`;
}
<div id="1">Click Me</div>
<div id="2">Click Me</div>
<div id="3">Click Me</div>
<div id="4">Click Me</div>
You can use the getElementById and addEventListener functions. It looks like this
[1, 2, 3, 4].forEach(id => {
document.getElementById(id).addEventListener('click', () => {
const el = document.getElementById(id + 1);
if (el) el.innerHTML = `test${id+1}`;
});
});
<div id='1'>a</div>
<div id='2'>b</div>
<div id='3'>c</div>
<div id='4'>d</div>
Here is a solution without using Ids
function myFunction(el, content) {
el.innerHTML = content;
}
<div onclick="myFunction(this, 'test2')">Click Me</div>
<div onclick="myFunction(this, 'test3')">Click Me</div>
<div onclick="myFunction(this, 'test4')">Click Me</div>
<div onclick="myFunction(this, 'test5')">Click Me</div>
Event Delegation
Event delegation is a pattern that optimizes event handling by registering an ancestor element of a group of descendant elements. By controlling what is ignored and what is triggered by an event, you can have a single element (ancestor in demo is <ul>/ event.currentTarget) listen for an event (click event in demo) for all of its descendant elements (all of the <li> in demo event.target).
Demo
Details are commented in demo
// Reference an ancestor element
var list = document.querySelector('ul');
// Register click event on ancestor element
list.onclick = clicker;
// Callback function pass the Event Object
function clicker(event) {
// Reference the clicked element (<li>...)
var clicked = event.target;
// Reference the element registered to the event (<ul>)
var ancestor = event.currentTarget;
// if the clicked element is NOT the registered element
if (clicked !== ancestor) {
// if the clicked element is an <li>...
if (clicked.matches('li')) {
// ...toggle the .on class
clicked.classList.toggle('on');
}
}
}
li {
cursor: pointer;
}
.on {
color: gold;
background: black;
}
<ul>
<li>ITEM 1</li>
<li>ITEM 2</li>
<li>ITEM 3</li>
<li>ITEM 4</li>
</ul>

How could i target a div and it's child to handle a click?

I have a <div class="stock"></div>wrapped around :
<div class="stockAdd"></div>
<div class="stockRemove"></div>
<div class="stockInput"></div>
I want to prevent a click inside my .stock to trigger a function. For now i have the following :
if ($(event.target).is('.stockInput') || $(event.target).is('.stockAdd') || $(event.target).is('.stockRemove')) {
console.log("Ajout stock");
return
}
Isn't there a better way to select thos three divs ? The $(event.target).is('.stock') don't get the job done when i click my nested divs.
Thanks
If I understand you correctly, you want to catch click events on .stockAdd, .stockRemove, and .stockInput, but not on other elements within .stock itself, is that correct?
If so, a delegated event can take care of that without any need to manually check the event target:
$('.stock').on('click', '.stockAdd, .stockRemove, .stockInput', function() {
alert("Clicked");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="stock">
<div class="stockAdd">stockAdd</div>
<div class="stockRemove">stockRemove</div>
<div class="stockInput">stockInput</div>
<div>No event</div>
</div>
I would strongly recommend against depending on event.target here; it's too fragile. Any HTML tags nested inside your desired targets would break things:
$('.stock').on('click', function(event) {
if (event.target.className=="stockAll") {
alert("clicked");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="stock">
<div class="stockAll">
This <b> will not work if someone clicks in the bold area</b> but works outside
</div>
</div>
You can add a separate class to all of them like .stock-inner and then grab them all with $('.stock-inner') or you can use a $("div[class^='stock-inner']) - this will grab the parent .stock div...
Also, to reject a click event within the handler you're gunna want to use e.preventDefault() where e is the event object.
the reason it doesn't work well on nested divs is they pass the conditional if in your example, to make it stricter you could add div to selector:
if ($(event.target).is('div.stockInput') || $(event.target).is('div.stockAdd') || $(event.target).is('div.stockRemove'))
You can attach the event on .stock and then filter using the event.target.
HTML
<div class="stock" style="border: 10px solid #000;">
<div class="stockAdd">Add</div>
<div class="stockRemove">Remove</div>
<div class="stockInput">Input</div>
</div>
JavaScript
$('.stock').on('click', function(e) {
if( e.target.className !== 'stock' ) {
console.log(e.target.className);
}
});
jsfiddle

How to specify dynamic element in javascript on() function?

I have approximately such structure:
<div class='container'>
<div class='element' data-id='1'></div>
<div class='element' data-id='2'></div>
<div class='element' data-id='2'></div>
</div>
Where .elements' are rendered dynamically.
So I wrote handler for these elements:
jQuery('.container').on('click', '.element', function () { //code })
But I need to do something with element, which was clicked.
How could I get clicked element?
The clicked element will be this in your event handler function.
jQuery('.container').on('click', '.element', function () {
// use "this" or "jQuery(this)", depending on your needs
})
Note that this will point to a DOM element, in your case a <div>.
You have to do something with the target of the event.
Something like :
jQuery('.container').on('click', '.element', function (event) {
var clickedelement = $(event.target);
//code
})
HTML:
<div class='container'>
<div class='element' data-id='1'/>
<div class='element' data-id='2'/>
<div class='element' data-id='2'/>
</div>
Javascript:
$(function () {
$('.container').on('click', '.element', function () {
$clickedElement = $(this);
$data-id = $clickedElement.attr('data-id');
});
});

Prevent event propagation using Google Closure Library

Using Google Closure Library:
How can I handle clicking of an element for example a div but prevent firing the event handler when the user clicks the child elements of that element.
For example in the following code I want to fire the event handler when user click div1 but when he/she clicks 'span1' I want another event handler to be called without firing the handler of div1.
<div style="width: 400px" id="div1">
<span id="span1">click me to reload</span>
click here to Toggle accordion
</div>
UPDATE
JS Code:
/**** accordion ***/
var panels = goog.dom.getElementsByClass('newsColumnHeader', goog.dom.getElement('accordionContainer'));
var anims = {};
var open = null;
goog.array.forEach(panels, function(pane){
var animation = new goog.ui.AnimatedZippy(pane, goog.dom.getNextElementSibling(pane));
goog.events.listen(animation, goog.ui.Zippy.Events.TOGGLE, zippyToggle);
anims[goog.getUid(animation)] = animation;
});
function zippyToggle(event) {
var uid = goog.getUid(event.target);
// simple logic - only one open panel in one time
if (event.expanded && uid != open) {
if (open) {
anims[open].setExpanded(false);
}
open = uid;
}
}
/******************/
var refreshVarzesh3 = goog.dom.getElement("btnRefreshVarzesh3");
if (refreshVarzesh3 != null) {
goog.events.listen(refreshVarzesh3, goog.events.EventType.CLICK, function(event) {
/*doing something but not toggling accordion pane*/
});
}
HTML CODE:
<body>
<div class="main">
<div class="top">
<div id="toolbar">
<img src="css/img/contact.png" alt="تماس، پیشنهاد، گزارش خطا" title="تماس، پیشنهاد، گزارش خطا"/>
</div>
<img src="css/img/football_news.gif" alt="آخرین اخبار فوتبال"/>
</div>
<div class="middle">
<div class="left"></div>
<div class="right">
<div class="accordion" id="accordionContainer">
<div class="newsColumnHeader">
<div class="buttons">
<img id="btnRefreshVarzesh3" src="css/img/refresh.png" alt="به روز رسانی" title="به روز رسانی"/>
</div>
<%=lbls.getString("Varzesh3News")%>
</div>
<div class="newsList" id="varzesh3NewsContainer"></div>
<div class="newsColumnHeader"><%=lbls.getString("PersepolisNews")%></div>
<div class="newsList" id="persepolisNewsContainer"></div>
<div class="newsColumnHeader"><%=lbls.getString("EsteghlalNews")%></div>
<div class="newsList" id="esteghlalNewsContainer"></div>
<div class="newsColumnHeader"><%=lbls.getString("NavadNews")%></div>
<div class="newsList" id="navadNewsContainer"></div>
</div>
</div>
</div>
<div class="bottom"></div>
</div>
for pure javascript developers the answer is here but if you use Google Closure Library the following code is enough:
event.stopPropagation();
in the event handler of that click you have to use preventDefault()
for example:
document.getElementById('div1').onclick = function (event) {
//your code
event.preventDefault();
}
Just for Reference All events in Google Closure are derived from goog.events.Event
http://docs.closure-library.googlecode.com/git/class_goog_events_Event.html
For Example : goog.events.BrowserEvents
So first one is stopPropagation
this.getHandler().listen(element ,goog.events.EventType.CLICK, function (e){
e.stopPropagation();
});
Second one is goog.events.Event.stopPropagation is a static method
which in turn calls above method
goog.events.Event.stopPropagation = function(e) {
e.stopPropagation();
};
Edit :
Please do read - Dangers of Event Propagation

Categories

Resources