Button duplicate not working in jquery? - javascript

I created a button(dupe of existed) onclick of existed button. But the newly created button is not going to create another button when I click.
Here is my code
$('.add-more, .dropdown button').click(function(event){
var elementToBeAdded;
if(event.target.nodeName === "IMG"){
elementToBeAdded = event.target.parentElement.parentElement.parentElement.parentElement;
}
else if(event.target.nodeName === "BUTTON"){
elementToBeAdded = event.target.parentElement.parentElement.parentElement;
}
else if(event.target.nodeName === "SPAN"){
elementToBeAdded = event.target.parentElement.parentElement;
}
var newElement = elementToBeAdded.outerHTML;
newElement = newElement.slice(0, 5) + "style='margin-top:25px' " + newElement.slice(5, newElement.length);
newElement = $(newElement)
$(elementToBeAdded).parent().append(newElement);
})
The above code working fine and creates the dupe button, But the dupe is unable to run the code on click. Please help me.

Add the click handler to the new element.
It's probably easier to move the main logic into a separate function so you can easily attach that function as the click handler.

if the element has the same class ie .add-more and .dropdown and its a button then this is the solution
$('.add-more, .dropdown button').on('click', function(event){
var elementToBeAdded;
if(event.target.nodeName === "IMG"){
elementToBeAdded = event.target.parentElement.parentElement.parentElement.parentElement;
}
else if(event.target.nodeName === "BUTTON"){
elementToBeAdded = event.target.parentElement.parentElement.parentElement;
}
else if(event.target.nodeName === "SPAN"){
elementToBeAdded = event.target.parentElement.parentElement;
}
var newElement = elementToBeAdded.outerHTML;
newElement = newElement.slice(0, 5) + "style='margin-top:25px' " + newElement.slice(5, newElement.length);
newElement = $(newElement)
$(elementToBeAdded).parent().append(newElement);
})

As shown in this same, already answered, question you'll have to use event delegation like this:
$(document).on('click', '.add-more, .dropdown button', function(event){
// ...
})
Because dynamically created elemenets dosen't have any event handler unless they are attached to them after they were created. So instead of making an event handler on the elements themselves, you can have it on an element (a parent of those elements) that you know for sure it will be there always (here I used document, it could be any other element, the condition is it have to be there always). You attach the event handler to that fixed element (document) and telling it that when ever an event occur (first argument), check if the target element match the selector (second argument '.add-more, .dropdown button'), if so then call the function (third argument) on that element.
WHY DO DYNAMICALLY CREATED ELEMENT NOT HAVE EVENT LISTENER?:
Because, this code right here:
$('selector').click(function(){
// ...
})
selects all the elements that match the selector ('selector') and loop through them (THE SELECTED ELEMENTS) one by one assigning the function passed as an event listener using basic JS function (addEventListener, attachEvent...). At this point when this code is run, your future dynamically created elements do not exist so they don't get attached to that event (because they do not exist yet). And by the time they do exist, this line of code $('selector').click(...) is already been executed (because javascript execute code instruction after the other, there's no comming back to a previously executed instruction). So another check to see if there is new elements that match will not happen. To understand here is a plain java script example:
function handleClick() {
alert("Yaay! A Click Happened!");
}
// consider we have three .btn elements in DOM at this point
var btns = document.querySelectorAll('.btn'); // three elements are selected
btns.forEach(function(btn){
btn.addEventListener('click', handleClick); // here too, just three elements get the event listener attached to them
});
// now we create another .btn
var div = document.creatElement('div');
div.className = '.btn':
// we have never ever ever ever ... called .addEventListener on the last element so clicking it will have no effect at all.

I have done this on my own. It's working.
var addBtns = document.querySelectorAll('.add-more, .dropdown button');
addClick(addBtns);
function addClick(addBtns){
Array.prototype.forEach.call(addBtns, function(addBtn) {
addBtn.addEventListener('click', addClickEvent);
});
}
function addClickEvent(e){
var elementToBeAdded;
if(event.target.nodeName === "IMG"){
elementToBeAdded = event.target.parentElement.parentElement.parentElement.parentElement;
}
else if(event.target.nodeName === "BUTTON"){
elementToBeAdded = event.target.parentElement.parentElement.parentElement;
}
else if(event.target.nodeName === "SPAN"){
elementToBeAdded = event.target.parentElement.parentElement;
} else{
return false;
}
var newElement = elementToBeAdded.outerHTML;
newElement = newElement.slice(0, 5) + "style='margin-top:25px' " + newElement.slice(5, newElement.length);
newElement = $(newElement)
$(elementToBeAdded).parent().append(newElement);
addClick(newElement);
}

Related

Javascript - Problem with modal close on click outside [duplicate]

I have searched for a good solution everywhere, yet I can't find one which does not use jQuery.
Is there a cross-browser, normal way (without weird hacks or easy to break code), to detect a click outside of an element (which may or may not have children)?
Add an event listener to document and use Node.contains() to find whether the target of the event (which is the inner-most clicked element) is inside your specified element. It works even in IE5
const specifiedElement = document.getElementById('a')
// I'm using "click" but it works with any event
document.addEventListener('click', event => {
const isClickInside = specifiedElement.contains(event.target)
if (!isClickInside) {
// The click was OUTSIDE the specifiedElement, do something
}
})
var specifiedElement = document.getElementById('a');
//I'm using "click" but it works with any event
document.addEventListener('click', function(event) {
var isClickInside = specifiedElement.contains(event.target);
if (isClickInside) {
alert('You clicked inside A')
} else {
alert('You clicked outside A')
}
});
div {
margin: auto;
padding: 1em;
max-width: 6em;
background: rgba(0, 0, 0, .2);
text-align: center;
}
Is the click inside A or outside?
<div id="a">A
<div id="b">B
<div id="c">C</div>
</div>
</div>
You need to handle the click event on document level. In the event object, you have a target property, the inner-most DOM element that was clicked. With this you check itself and walk up its parents until the document element, if one of them is your watched element.
See the example on jsFiddle
document.addEventListener("click", function (e) {
var level = 0;
for (var element = e.target; element; element = element.parentNode) {
if (element.id === 'x') {
document.getElementById("out").innerHTML = (level ? "inner " : "") + "x clicked";
return;
}
level++;
}
document.getElementById("out").innerHTML = "not x clicked";
});
As always, this isn't cross-bad-browser compatible because of addEventListener/attachEvent, but it works like this.
A child is clicked, when not event.target, but one of it's parents is the watched element (i'm simply counting level for this). You may also have a boolean var, if the element is found or not, to not return the handler from inside the for clause. My example is limiting to that the handler only finishes, when nothing matches.
Adding cross-browser compatability, I'm usually doing it like this:
var addEvent = function (element, eventName, fn, useCapture) {
if (element.addEventListener) {
element.addEventListener(eventName, fn, useCapture);
}
else if (element.attachEvent) {
element.attachEvent(eventName, function (e) {
fn.apply(element, arguments);
}, useCapture);
}
};
This is cross-browser compatible code for attaching an event listener/handler, inclusive rewriting this in IE, to be the element, as like jQuery does for its event handlers. There are plenty of arguments to have some bits of jQuery in mind ;)
How about this:
jsBin demo
document.onclick = function(event){
var hasParent = false;
for(var node = event.target; node != document.body; node = node.parentNode)
{
if(node.id == 'div1'){
hasParent = true;
break;
}
}
if(hasParent)
alert('inside');
else
alert('outside');
}
you can use composePath() to check if the click happened outside or inside of a target div that may or may not have children:
const targetDiv = document.querySelector('#targetDiv')
document.addEventListener('click', (e) => {
const isClickedInsideDiv = e.composedPath().includes(targetDiv)
if (isClickedInsideDiv) {
console.log('clicked inside of div')
} else {
console.log('clicked outside of div')
}
})
I did a lot of research on it to find a better method. JavaScript method .contains go recursively in DOM to check whether it contains target or not. I used it in one of react project but when react DOM changes on set state, .contains method does not work. SO i came up with this solution
//Basic Html snippet
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="mydiv">
<h2>
click outside this div to test
</h2>
Check click outside
</div>
</body>
</html>
//Implementation in Vanilla javaScript
const node = document.getElementById('mydiv')
//minor css to make div more obvious
node.style.width = '300px'
node.style.height = '100px'
node.style.background = 'red'
let isCursorInside = false
//Attach mouseover event listener and update in variable
node.addEventListener('mouseover', function() {
isCursorInside = true
console.log('cursor inside')
})
/Attach mouseout event listener and update in variable
node.addEventListener('mouseout', function() {
isCursorInside = false
console.log('cursor outside')
})
document.addEventListener('click', function() {
//And if isCursorInside = false it means cursor is outside
if(!isCursorInside) {
alert('Outside div click detected')
}
})
WORKING DEMO jsfiddle
using the js Element.closest() method:
let popup = document.querySelector('.parent-element')
popup.addEventListener('click', (e) => {
if (!e.target.closest('.child-element')) {
// clicked outside
}
});
To hide element by click outside of it I usually apply such simple code:
var bodyTag = document.getElementsByTagName('body');
var element = document.getElementById('element');
function clickedOrNot(e) {
if (e.target !== element) {
// action in the case of click outside
bodyTag[0].removeEventListener('click', clickedOrNot, true);
}
}
bodyTag[0].addEventListener('click', clickedOrNot, true);
Another very simple and quick approach to this problem is to map the array of path into the event object returned by the listener. If the id or class name of your element matches one of those in the array, the click is inside your element.
(This solution can be useful if you don't want to get the element directly (e.g: document.getElementById('...'), for example in a reactjs/nextjs app, in ssr..).
Here is an example:
document.addEventListener('click', e => {
let clickedOutside = true;
e.path.forEach(item => {
if (!clickedOutside)
return;
if (item.className === 'your-element-class')
clickedOutside = false;
});
if (clickedOutside)
// Make an action if it's clicked outside..
});
I hope this answer will help you !
(Let me know if my solution is not a good solution or if you see something to improve.)

How to keep extra fields added by js on refresh

var container = document.createElement("lastExp");
container.innerHTML = 'html code new form field';
document.getElementById("lastExp").appendChild(container);
It's simple i click button extra form field is added.
Question: When i refresh page how to not lose this extra fields on my form.
Stack Overflow is not the place to write code, but this will sits here in case someone besides OP need.
It's a minimal example--getting started--with localStorage. As I mentioned, under the hood, you have to append that element every time the page is loaded.
The snippet won't work here, unfortunately because the iframe is sandbox'd. Head over to my hub to experiment it.
var container = document.getElementById('container'),
toggle = document.getElementById('toggle');
element = null;
// initial check
init();
// add click event and listen for clicks
toggle.onclick = function() {
// both cases will update localStoage _inputIsThere
// if element is null -- doesn't exists, then add it
if (element == null) {
add();
} else {
// remove the element
remove();
}
}
// check if key exists in localStorage; this is where all the "magic" happens.
function init() {
var exists = localStorage.getItem('_inputIsThere');
if (exists && exists == 'true') {
add();
}
}
function remove() {
element.remove();
element = null;
// update key in localStorage to false
localStorage.setItem('_inputIsThere', false);
}
// adds the input and updates
function add() {
var e = document.createElement('input');
e.type = 'text';
element = e;
container.appendChild(e);
// update key in localStorage to true
localStorage.setItem('_inputIsThere', true);
}
<button id="toggle">Add/Remove</button>
<div id="container"></div>

applying an event handler to newly created objects

So my goal is to have 5 boxes and every time one box is clicked a new box appears. The code I wrote for that is this:
window.onload = function(){
var boxList = document.getElementsByClassName("box");
for(i = 0; i< boxList.length;i++){
boxList[i].onclick = clickHandler;
}
}
function clickHandler(eo){
if(eo.target.style.backgroundColor != "black") {
eo.target.style.backgroundColor = "black";
var box = document.createElement("div");
box.setAttribute("class","box");
box.setAttribute("id",document.getElementsByClassName("box").length++);
document.getElementById("Master").appendChild(box);
}
else eo.target.style.backgroundColor = "white";
}
The class of all the divs is "box" and I just add a new id to every new box. My problem is that the event handler doesn't seem to work for the newly created boxes. How could that be solved?
Many thanks in advance!
box.onclick = clickHandler;
There are more elegant ways, but as that's what you're already doing, there's no harm doing what you're doing, now.
In a different world, you might do something like:
var master = document.querySelector("#master");
master.addEventListener("click", clickHandler);
function clickHandler (e) {
var box = e.target;
var newBox;
var totalBoxes = master.querySelectorAll(".box").length;
if (!box.classList.contains("box")) {
return; // not a box
}
if (isBlack(box)) {
changeColour(box, "white");
} else {
newBox = makeNewBox(totalBoxes + 1);
master.appendChild(newBox);
changeColour(box, "black");
}
}
I don't have to worry about further click-handling beyond that, if all of the boxes are descendants of #master.
makeNewBox here is simply separating the creation of the object from what you actually want to do with it.
You will need to add an onclick event to your newly added box.
box.onclick = clickHandler;
If you create boxes dynamically after the window.onload handler has already run, then you will have to run some additional code on those dynamically created boxes that assigns the click handler to them after they have been created.
function clickHandler(eo){
if(eo.target.style.backgroundColor != "black") {
eo.target.style.backgroundColor = "black";
var box = document.createElement("div");
box.setAttribute("class","box");
// add this line of code to assign the click handler
box.onclick = clickHandler;
box.setAttribute("id",document.getElementsByClassName("box").length++);
document.getElementById("Master").appendChild(box);
}
else eo.target.style.backgroundColor = "white";
}
Or, you can use delegated event handling and handle the events from a common parent that is not dynamically created.
Delegated event handling uses "event bubbling" where events bubble up their parent chain so you can attach a click handler to a common parent and then check e.target in that click handler to see if the click occurred on one of your box elements and then process it one place. In cases of dynamically added content, this can work very well.
Delegated event handling in your code would look something like this:
window.onload = function(){
// put click handler on common box parent and use event bubbling
document.getElementById("Master").addEventListener("click", clickHandler);
}
function clickHandler(eo){
// if this click occurred on one of my boxes
if (hasClass(eo.target, "box"))
if(eo.target.style.backgroundColor != "black") {
eo.target.style.backgroundColor = "black";
var box = document.createElement("div");
box.setAttribute("class","box");
box.setAttribute("id",document.getElementsByClassName("box").length++);
document.getElementById("Master").appendChild(box);
}
else eo.target.style.backgroundColor = "white";
}
}
// utility function for checking a class name
// could also use .classList with a polyfill for older browsers
function hasClass(elem, cls) {
var str = " " + elem.className + " ";
var testCls = " " + cls + " ";
return(str.indexOf(testCls) !== -1) ;
}

How to add an event Listener to multiple objects via the class name

I have a set of scrolling objects with text in them. I have surrounded said text with a div and a class name of "scrollContent". I have added an onscroll attribute that calls my method.
I have come across the .addEventListener feature and want to add a listener when any divs with the class name scrollContent is scrolled, call my function.
Is this possible and how?
function checkScroll(scrollEle) {
var topLG = getTopLG(scrollEle);
if(scrollEle.scrollTop < 10){
topLG.style.display = "none";
}else{
if(topLG.hasAttribute("style")){
topLG.removeAttribute("style");
}
}
}
var scrollDivs = document.getElementsByClassName("scrollContent");
for (var i =0; i<scrollDivs.length; i++){
scrollDivs[i].addEventListener('scroll', checkScroll(scrollDivs[i]), false)
}
Use event delegation. Something like:
// somecontainerDiv can be document, document.body or any Element
// containing your elements having class 'scrollContent'
somecontainerDiv.addEventListener('scroll', scrollHandling);
function scrollHandling(e){
var originator = e.target || e.srcElement;
if (!/scrollContent/i.test(originator.className) {return true;}
return checkScroll(e); // or insert checkScroll code here
}

Javascript Detect click event outside of div [duplicate]

This question already has answers here:
How do I detect a click outside an element?
(91 answers)
Closed 1 year ago.
The community reviewed whether to reopen this question last year and left it closed:
Original close reason(s) were not resolved
I have a div with id="content-area", when a user clicks outside of this div, I would like to alert them to the fact that they clicked outside of it. How would I use JavaScript to solve this issue?
<div id = "outer-container">
<div id = "content-area">
Display Conents
</div>
</div>
In pure Javascript
Check out this fiddle and see if that's what you're after!
document.getElementById('outer-container').onclick = function(e) {
if(e.target != document.getElementById('content-area')) {
document.getElementById('content-area').innerHTML = 'You clicked outside.';
} else {
document.getElementById('content-area').innerHTML = 'Display Contents';
}
}
http://jsfiddle.net/DUhP6/2/
The Node.contains() method returns a Boolean value indicating whether a node is a descendant of a given node or not
You can catch events using
document.addEventListener("click", clickOutside, false);
function clickOutside(e) {
const inside = document.getElementById('content-area').contains(e.target);
}
Remember to remove the event listened in the right place
document.removeEventListener("click", clickOutside, false)
Bind the onClick-Event to an element that is outside your content area, e.g. the body. Then, inside the event, check whether the target is the content area or a direct or indirect child of the content area. If not, then alert.
I made a function that checks whether it's a child or not. It returns true if the parent of a node is the searched parent. If not, then it checks whether it actually has a parent. If not, then it returns false. If it has a parent, but it's not the searched one, that it checks whether the parent's parent is the searched parent.
function isChildOf(child, parent) {
if (child.parentNode === parent) {
return true;
} else if (child.parentNode === null) {
return false;
} else {
return isChildOf(child.parentNode, parent);
}
}
Also check out the Live Example (content-area = gray)!
I made a simple and small js library to do this for you:
It hijacks the native addEventListener, to create a outclick event and also has a setter on the prototype for .onoutclick
Basic Usage
Using outclick you can register event listeners on DOM elements to detect whether another element that was that element or another element inside it was clicked. The most common use of this is in menus.
var menu = document.getElementById('menu')
menu.onoutclick = function () {
hide(menu)
}
this can also be done using the addEventListener method
var menu = document.getElementById('menu')
menu.addEventListener('outclick', function (e) {
hide(menu)
})
Alternatively, you can also use the html attribute outclick to trigger an event. This does not handle dynamic HTML, and we have no plans to add that, yet
<div outclick="someFunc()"></div>
Have fun!
Use document.activeElement to see which of your html elements is active.
Here is a reference:
document.activeElement in MDN
$('#outer-container').on('click', function (e) {
if (e.target === this) {
alert('clicked outside');
}
});
This is for the case that you click inside the outer-container but outside of the content-area.
Here is the fiddle : http://jsfiddle.net/uQAMm/1/
$('#outercontainer:not(#contentarea)').on('click', function(event){df(event)} );
function df(evenement)
{
var xstart = $('#contentarea').offset().left;
var xend = $('#contentarea').offset().left + $('#contentarea').width();
var ystart = $('#contentarea').offset().top;
var yend = $('#contentarea').offset().top + $('#contentarea').height();
var xx = evenement.clientX;
var yy = evenement.clientY;
if ( !( ( xx >= xstart && xx <= xend ) && ( yy >= ystart && yy <= yend )) )
{
alert('out');
}
}
use jquery as its best for DOM access
$(document).click(function(e){
if($(e.target).is("#content-area") || $(e.target).closest("#content-area").length)
alert("inside content area");
else alert("you clicked out side content area");
});
Put this into your document:
<script>
document.onclick = function(e) {
if(e.target.id != 'content-area') alert('you clicked outside of content area');
}
</script>
Here is a simple eventListener that checks all parent elements if any contain the id of the element. Otherwise, the click was outside the element
html
<div id="element-id"></div>
js
const handleMouseDown = (ev) => {
let clickOutside = true
let el = ev.target
while (el.parentElement) {
if (el.id === "element-id") clickOutside = false
el = el.parentElement
}
if (clickOutside) {
// do whatever you wanna do if clicking outside
}
}
document.addEventListener("mousedown", handleMouseDown)

Categories

Resources