Event Delegation: Affecting more elements than it should - javascript

I'm learning event delegation, and I encounter a problem.
At first, when I did the first draft, if I clicked in the < span > it would only delete the text and not the button, so I modified it. Later, when clicking the container div it deleted the whole thing, so I changed it again.
Right now it's functional, but it seems to me that it could be written more generically (without needing to add the class names, just the id of the container) and in a more efficient way, I feel there is a lot more code than it should be.
And one more thing: It should work with dynamically added elements.
Any help would be very appreciated!
function getTarget(e) {
return e.target;
}
function remove(e) {
var target = getTarget(e);
target.parentNode.removeChild(target);
}
function remove1(e) {
var target = getTarget(e);
var parent = target.parentNode;
parent.parentNode.removeChild(parent);
}
document.getElementById("contenedor").addEventListener("click", function (e) {
if (e.target && e.target.nodeName === "DIV" && e.target.classList.contains("bot")) {
remove(e);
}
if (e.target && e.target.nodeName === "SPAN") {
remove1(e);
}
document.getElementById("parrafo").textContent = "Hice click en";
});
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="contenedor">
<div class="bot" id="boton" style="width:200px; height:50px; background-color: red"><span>asdasd</span></div>
<br>
<div class="bot" id="boton1" style="width:200px; height:50px; background-color: red"><span>asdasd</span></div>
<br>
<div class="bot" id="boton2" style="width:200px; height:50px; background-color: red"><span>asdasd</span></div>
<br>
<div class="bot" id="boton3" style="width:200px; height:50px; background-color: red"><span>asdasd</span></div>
<br>
<div class="bot" id="boton4" style="width:200px; height:50px; background-color: red"><span>asdasd</span></div>
<br>
<div class="bot" id="boton5" style="width:200px; height:50px; background-color: red"><span>asdasd</span></div>
</div>
<br>
<script src="script.js"></script>
</body>
</html>

In a JS event, e.target is the element the action (click) is performed on and this the element the code is attached to. That can be used to check if the parentNode is the div the click was attached to (well, the same could be done by checking if the parent is the div by its id, but since it's an event delegation excercise, this is more fun :) )
document.getElementById("contenedor").addEventListener("click", function (e) {
var target = e.target;
if(target!==this){ //if the div itself is clicked do nothing
while(target.parentNode !== this) //loop up until it's a direct parent, this also works with multiple nested elements
target = target.parentNode;
target.parentNode.removeChild(target);
}
document.getElementById("parrafo").textContent = "Hice click en";
});
fiddle
As a side note, instead of adding a <BR> under each div, you can also alter the margin through css with something like
.bot{
margin-bottom:20px;
}
This has the advantage that removed elements hold the same space (unless of course, that is not the intention ;) )
Example: fiddle

Related

Get the cursor out of span inside contenteditable

In the following snippet if the user types something after of TEST it automatically becomes red. This is because user typed text is going inside the span. While it may be the desired behaviour sometimes, often user wants to type a new word and get out of span.
Is there a way to toggle between the two behaviours. Ideally, I would want that if the user presses right arrow key, they should get out of span.
.bg-red{
background: red;
}
<div id="wrapper" contenteditable="true">
<span class="bg-red">TEST</span>
</div>
you can try like this
.bg-red{
background: red;
}
<div id="wrapper" >
<span class="bg-red" style="float:left" contenteditable="true">TEST</span> <span contentEditable="true" style="float:left">Your Comment</span>
</div>
Dear try below its simple.
$(document).ready(function () {
$('<span id="newline"> </span>').insertAfter('.bg-red');
$('#wrapper').click(function () {
if ($("#newline").length) {
$("#newline").focus();
}
else {
$("#newline").focus();
}
});
$("#wrapper").on("keypress", function () {
$("#newline").focus();
})
});
.bg-red {
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrapper" contenteditable="true">
<span class="bg-red">TEST</span>
</div>
Here is a Pure JS execution of what you requested.
You add an event listener to listen for keypress.
You identify the key you desire.
Execute whatever you want.
Best Wishes
document.addEventListener('keydown', indentifyKeyPressed);
const wrapper = document.getElementById("wrapper");
function indentifyKeyPressed(event) {
if (event.key === "ArrowRight") {
//Creating a new element
const newElement = document.createElement("span")
newElement.setAttribute("class", "bg-green")
newElement.setAttribute("contenteditable", "true")
wrapper.appendChild(newElement).focus()
}
}
.bg-red {
background: red;
}
.bg-green {
background: green;
}
<div id="wrapper" >
<span class="bg-red" contenteditable="true" >TEST</span>
</div>

jQuery - detect if div has 2 classes

I am using jQuery to detect a click like this..
$(".clickable_link").click(function() {
console.log('Link Clicked');
}
<div class="clickable_link">
Click Me
</div>
<div class="clickable_link special">
Click Me
</div>
I am trying to determine if the div with 'special' has been clicked or if it just the div with 'clickable_link'.
What is the best way to do this? Should I use hasclass or is filter a better choice?
Something like this:
$(".click").click(function(){
if ($(this).hasClass("special")) {
alert("Its Special!");
}
});
.click {
width:100px;
height:50px;
background-color:#333;
float:left;
margin:10px;
color:#fff;
text-align:center;
padding-top:25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="click">Not Special</div>
<div class="click special">SPECIAL!</div>
As an alternative to .hasClass, you can use .is, which allows for any selector, not just checking for a class.
if($(this).is(".special")) { ...
$(".clickable_link").click(function() {
if ($(this).is(".special")) {
alert("special clicked");
} else {
alert("nope");
}
});
.special { color: red; }
.clickable_link { cursor: pointer; margin-bottom: 0.5em; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="clickable_link">
Click Me
</div>
<div class="clickable_link special">
Click Me
</div>
$('#id1').click(function() {
var x = $('#id1').attr('class') //dont use classname to fetch the element
x = x.split(' ')
if (x.length > 2)
alert('id1 has more than 2 classes');
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='id1' class='myclass mysubclass'>dfdfdfsdfds</div>
You can bind different event handlers depending on whether the special class exists.
$(".clickable_link.special").click(function()
console.log("Special link clicked");
})
$(".clickable_link:not(.special)").click(function() {
console.log("Ordinary link clicked");
});
If there's common code for both types of links, you can put that in another function that gets called by each handler.
As example, use can can detect count of classes as like it:
$(".clickable_link").click(function() {
var classList = $(this).attr('class').split(/\s+/);
console.log(`count ${classList.length}`);
}

HTML and Javascript - Detecting which div box was clicked?

If I have multiple div boxes lined up (not overlapping), how can I detect which box is clicked?
For example, here is pseudocode:
HTML:
<div id="box1" onClick="clicked()">Box 1</div>
<div id="box2" onClick="clicked()">Box 2</div>
<div id="box3" onclick="clicked()">Box 3</div>
JS:
function clicked(){
var first="box1";
var second="box2";
var third="box3";
if (the div id of what you clicked is equal to first)
/*do something here*/
if (the div id of what you clicked is equal to second)
/*do something here*/
etc
etc
}
My main problem is that I don't know how to properly write the if statement. I'm not sure how to get the div's id that you clicked in JavaScript. I'm thinking of something like this:
if (document.getElementById() = first)
/*do stuff*/
I'm aware that I can solve this problem by having three different functions such as clicked1(), clicked2(), and clicked3(), but I would prefer not to have so many functions.
Any help is appreciated, thank you.
Pure Javascript has a built in target in the event object. This is basically the opposite of getElementById, its basically getIdByElement(though this method doesn't exist). To access it all you need to do is edit your HTML from onClick="clicked()" to onClick="clicked(event)" and change your clicked function into code similar to this:
function clicked(event) {
var id = event.target.id,
first = 'box1',
second = 'box2',
third = 'box3';
if(id === first) {
...
} else if(id === second) {
...
} else if(id === third) {
...
}
}
To explain why this works, when a JavaScript event is fired you get an object about it, it looks like this:
This is so that you can get certain details about what happened. In this case, you wanted the target id. This works by selecting all divs on the page. Also to shorten the code if you want, you can pass in this instead and do this.id. Such as:
function clicked(reference) { //pass in this instead of event
let id = reference.id;
...
}
Here is an example of it in work:
function clicked(event) {
let p = document.getElementById('clicked-item')
p.textContent = event.target.id + ' clicked';
}
<div id="box1" onClick="clicked(event)">Box 1</div>
<div id="box2" onClick="clicked(event)">Box 2</div>
<div id="box3" onclick="clicked(event)">Box 3</div>
<p id="clicked-item">none clicked</p>
It is a good idea to separate HTML and JS(though not 100% necessary). So to remove the onClick attribute on each element do something like this:
let selector = document.getElementsByTagName('div')
for(let element of selector) {
element.addEventListener('click', function(event) {
clicked(event);
});
}
The code starts by getting all elements that are a div with getElementsByTagName, though you can use other selectors too. Then using a for loop we loop through all the divs and add an onClick event running clicked.
You could make this work using inline event handlers but it'd be better to move your binding code to your actual scripts. You can still use one function, just apply it to each element.
The click handler will receive an event object which gives information about the click. Part of that is the .target property which will give you the source of the click event i.e, the element you clicked on.
function clicked(e) {
var target = e.target;
console.log(target.id);
}
document.querySelector('#box1').addEventListener('click', clicked);
document.querySelector('#box2').addEventListener('click', clicked);
document.querySelector('#box3').addEventListener('click', clicked);
.box {
float: left;
width: 100px;
height: 100px;
margin-right: 2px;
background-color: #000;
color: #EEE;
}
<div id="box1" class="box">Box 1</div>
<div id="box2" class="box">Box 2</div>
<div id="box3" class="box">Box 3</div>
If you're hellbent on using inline bindings, the simplest way to do this would be to pass this into your function call. That will pass the element directly.
function clicked(target) {
console.log(target.id);
}
.box {
float: left;
width: 100px;
height: 100px;
margin-right: 2px;
background-color: #000;
color: #EEE;
}
<div id="box1" class="box" onclick="clicked(this)">Box 1</div>
<div id="box2" class="box" onclick="clicked(this)">Box 2</div>
<div id="box3" class="box" onclick="clicked(this)">Box 3</div>
By adding clicked(this) it selects the div you click on and returns that specific div's data.
<div id="box1" onClick="clicked(this)">Box 1</div>
<div id="box2" onClick="clicked(this)">Box 2</div>
<div id="box3" onclick="clicked(this)">Box 3</div>
By adding the div as a parameter it specifies the div you clicked on's internal data, and adding a switch statement to trigger a specific response to each div.
function clicked(div) {
if(div.id = 'box1') {
console.log('1');
} else if(div.id = 'box2') {
console.log('2');
} else if(div.id = 'box3') {
console.log('3');
}
}

Prevent body's onclick function inside div?

<body>
<div>
</div>
</body>
<script>
window.onclick = function() {do something;}
</script>
How do I prevent clicks inside of the div from carrying out the body's onclick function?
Try substituting <script> element for <style> element , utilizing e.target.tagName to determine if clicked element is DIV , return false if clicked element is DIV , else log clicked element to console
div {
width: 100px;
height: 100px;
border: 2px dotted tomato;
}
<body>
<div>
click
</div>
</body>
<script>
window.onclick = function(e) {
if (e.target.tagName === "DIV") return false
// do something;
else console.log(this)
}
</script>
If you only need to support modern browsers (>=IE11), use pointer-events:
div { pointer-events: none; }
Note that this will also inhibit all kinds of mouse-related effects, including hover.

Closing popup div in JavaScript

Can I get help correcting the code below? You can just copy and paste and try it yourself. Onmouseover the popup div appears. If I click X the popup div should close but it doesn't. Only doubleclicking X closes the popup div. Onmouseover it should always display a popup div though.
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<style type="text/css">
.container {
display:block;
width:500px;
height:200px;
border:1px solid green;
}
.advert {
float:right;
overflow:hidden;
width:100px;
height:30px;
border:1px solid red;
}
.close {
float:right;
width:20px;
height:28px;
cursor:pointer;
border:1px solid black;
}
</style>
<body>
<div class="container" onmouseover='getad(39);' onmouseout='hidead(39);changeback(39);'>
<div class='advert' id="39" style="display:none;"><div class="close">X</div></div>
<input type="text" value="1" id="ad39" />
</div>
<div class="container" onmouseover='getad(40);' onmouseout='hidead(40);changeback(40);'>
<div class='advert' id="40" style="display:none;"><div class="close">X</div></div>
<input type="text" value="1" id="ad40" />
</div>
<script type="text/javascript">
function getad(number) {
if(document.getElementById('ad'+number).value==1) {
if(document.getElementById(number).style.display == "none") {
document.getElementById(number).style.display = "block";
}
}
}
function hidead(number) {
if(document.getElementById('ad'+number).value==1) {
if(document.getElementById(number).style.display == "block") {
document.getElementById(number).style.display = "none";
}
}
}
function closead(number) {
document.getElementById('ad'+number).value = 0;
if(document.getElementById(number).style.display == "block") {
document.getElementById(number).style.display = "none";
}
}
function changeback(number) {
if(document.getElementById('ad'+number).value==0) {
document.getElementById('ad'+number).value = 1;
}
}
</script>
</body>
</html>
You IDs are wrong:
<div class='advert' id="39" style="display:none;">
<div class='advert' id="40" style="display:none;">
should be:
<div class='advert' id="ad39" style="display:none;">
<div class='advert' id="ad40" style="display:none;">
I tried your code in firefox and it works.
In IE8, it does not work.
This is the main reason why you should never write native Javascript...
Use JQuery or another JS framework.
First, it will make your code cross browser compatible.
Second, only 1 line of code will do what you need to do ;-)
Something like $(#39).hide() or $(#39).show()
The problem isn't that your ad isn't being removed. It's that in order to click the link that triggers the hidead() function, you must also be hovering the mouse cursor over the div that triggers getad() on mouseover.
So what is actually executing if you step through the actions is this.
Click event triggers on the tag for the "X-link"
closead(number) fires and executes it's code.
Mouseout event fires and propagates to the parent
hidead(number) fires and executes.
Mouseover event fires and propagates to the parent
getad(number) fires and executes.
So your event is being unloaded, then immediately reloaded. Perhaps if you could provide some context, we could help you make this workable. I'm not sure under what circumstances you want to load an ad on mouseover, hide it on mouseout, and give the user a close button. That just seems like a lot of loading/unloading/flashing content that's going to annoy your visitor more than simply having a static ad that reloads every X seconds via AJAX or something.

Categories

Resources