Removing dynamically created elements with vanilla JavaScript by clicking on them - javascript

I wrote the code below to dynamically add li elements to a ul element. I want the user to be able to click on any one of them and have that li item removed. I know how to do this with JQuery but I want to know how to do it with vanilla JavaScript.I understand that removeChild() is the only method at my dispose to do this but I am a bit confused as to how to use it to accomplish the task at hand.
Thank you.
http://jsfiddle.net/3wk0866o/
HTML
<form id="input-form">
<input id="input-field" type = "text"/>
<button>Submit</button>
</form>
<ul id="list" >
</ul>
JavaScript
var form = document.getElementById("input-form");
function getInput(event){
event.preventDefault();
var inputValue = document.getElementById("input-field").value
form.reset();
document.getElementById("list").innerHTML += "<li>"+ inputValue +"</li>";
}
form.addEventListener("submit",getInput,false)

Try this:
http://jsfiddle.net/3wk0866o/1/
I just added this listener function:
function removeItem(e) {
var target = e.target;
if(target.tagName !== 'LI') return;
target.parentNode.removeChild(target);
}
list.addEventListener('click', removeItem);
It adds an event listener to the "list" UL element, and listens for clicks inside of it. e.target is the element clicked, and if the element clicked isn't a LI element, then the function just returns. If it is, then it removes the element and all of its children.
If you want to know how the last bit that removes the element works:
target.parentNode finds the parent element of the clicked LI element (UL), and then you just simply call removeChild on that node, since LI is a child element of UL. You can also use the remove method on the element directly, but that is not well supported yet.
Note that you might run into problems if your LI element has children; in that case, the target might show up as one of LI's children and not as LI. To solve that you can use a loop that walks through the DOM until it gets to an UL element, or until it finds a LI element to remove:
http://jsfiddle.net/3wk0866o/3/
function removeItem(e) {
var target = e.target;
while(target.tagName !== 'UL') {
if(target.tagName === 'LI') {
return target.parentNode.removeChild(target);
}
target = target.parentNode;
}
}
list.addEventListener('click', removeItem);
If your LI elements will only have text inside of them, then the first solution is enough.
Good luck.

You could add an onclick event listener directly to the new child.
function getInput(event){
event.preventDefault();
var inputValue = document.getElementById("input-field").value
console.log(inputValue)
form.reset(); // _______________Reset method
// Create new element.
var new_li = document.createElement('li');
new_li.innerHTML = inputValue;
// When it is clicked, remove it.
new_li.onclick = function() {
this.remove();
};
// Append element as child to list.
document.getElementById("list").appendChild(new_li);
}
JSFiddle

you can use parent.removeChild(child) to remove the item but you might have problem with finding the child because the item has been added on the fly.
2 suggestion:
add the item in the list as you add them to the list and then grab them from the list instead of finding them on the page.
use .On function to attach click event and then use this in the event to grab them.

Related

Dom Traversing the Dom with JavaScript but event not hitting the Html Element

I want to add delete functionality to a button on an Li element that is dynamically created by Javascript but I can't seem to be able to get the event listener to hit the target button.
I tried adding it right away by doing
var trashButton = document.getElementsByClassName("deleteListItemButton");
trashButton.addEventListener('click',removeLiItem);
but I got an unhandled exception error
var idForLiElement =1;
document.getElementById("addTaskId").addEventListener('click', function(){
var valueFromTextBox = document.getElementById("textBoxId").value;
if(valueFromTextBox) addItemToDo(valueFromTextBox);
});
function addItemToDo(valueFromTextBox){
var unorderedList = document.getElementById("toDoId")
var listElement = document.createElement("li");
listElement.className ="listItem";
listElement.innerHTML = valueFromTextBox;
listElement.id =Number(idForLiElement);
idForLiElement ++;
//puts the newest list element before the last element
unorderedList.insertBefore(listElement, unorderedList.childNodes[0]);
//creates the div that will contain both buttons in each list element
var buttonsContainer = document.createElement("div");
buttonsContainer.className ="listItemButtonContainer";
//creates the delete button and assigns it a class name
var deleteButton = document.createElement("Button")
deleteButton.className ="deleteListItemButton";
//creates the complete button and assigns it a class name
var completeButton = document.createElement("Button")
completeButton.className ="completeListItemButton";
//creates the delete image tag and assigns it a class name
var trashImageTag = document.createElement("i")
trashImageTag.className = "fa fa-trash fa-2x";
//creates the check mark button and assigns it a class name
var checkMarkImageTag = document.createElement("i")
checkMarkImageTag.className= "fa fa-check fa-2x";
//appends delete image tag to delete button
deleteButton.appendChild(trashImageTag);
//appends check mark image tag to complete button
completeButton.appendChild(checkMarkImageTag);
//appends delete button to button container
buttonsContainer.appendChild(deleteButton);
//appends complete button to button container
buttonsContainer.appendChild(completeButton)
//appends button container to list element
listElement.appendChild(buttonsContainer);
};
var trashButton = document.getElementsByClassName("deleteListItemButton");
for (i = 0; i < trashButton.length; i++) {
trashButton[i].addEventListener('click',removeLiItem)
};
function removeLiItem(e){
console.log(this)
};
I just want the event listener to hit console.log so I know the button is working
Attach the event to the element you've just created
deleteButton.addEventListener('click', function() { console.log('hit!') })
I want to add delete functionality to a button on an Li element that is dynamically created by javascript but I cant seem to be able to get the event listener to hit the target button.
The elements are dynamically created, so by the time the elements are created, the for loop where you add the event listeners has already executed.
This is what event propogation is for. Let the parent element (ul) listen to event clicks instead of having each child hold the responsibility. That way it doesnt matter how many children elements are added, momma (parent element) will always be listening for clicks.
You can do something like this:
// on your ul element
const itemList = document.querySelector(".item-list");
// listen for click on here
itemList.addEventListener('click', removeLiItem);
// you can access the actual element through the event's `target`
function removeLiItem (event) {
if (event.target.classList.contains('deleteListItemButton') {
// remove element
}
}

How to pass events of html element with the drop in DND API of HTML5?

My question is regarding the drag and drop api of html. I want to do it natively but I lose my event handlers after dropping an element. As I don't know how to set all data of my html in 'dataTransfer' object, I am not able to do it.
Basically I was making a list where the list items can be swapped by drag and drop. I made my list item dynamically like this:
var div1 = document.createElement("div");//the span element to contain text
var span = document.createElement("span");
//the textnode inside of div1 at starting
var txt1 = document.createTextNode(textdata);
//the option button on div1
var optionBtn = document.createElement("button");
//the option button text
var optionText = document.createTextNode("options");
span.appendChild(txt1);
div1.appendChild(span);
optionBtn.appendChild(optionText);
optionBtn.addEventListener("click",function(){
console.log("clicked on options")
});
div1.appendChild(optionBtn);
div1.classList.add("draggableDiv");//this div1 is later appended inside my html
I put the above code in a function and call this function inside the forEach of an array which consists of 'textdata':
var textdatas = ["a","b","c"];
What I am doing for DnD is given below. For each list item that I added above, I do this:
//element that I am dragging
elem.addEventListener("dragstart",function(e){
e.dataTransfer.setData('text/html', this.innerHTML);
dragSrcEl = this;
});
//element where I am dropping
elem.addEventListener("drop",function(e){
if (e.stopPropagation) {
e.stopPropagation(); // Stops some browsers from redirecting.
}
if (dragSrcEl != this) { // the dragSrcEl contains the dragging element's data
dragSrcEl = this.innerHTML;
this.innerHTML = e.dataTransfer.getData('text/html');
}
});
Now the problem is that I don't know how to pass the events of 'optionBtn'(or any event of any child element) in the 'dataTransfer' of DnD.
Please provide a solution for this. Any help will be appreciated.

Attaching Click Event to DIV Using jQuery Library

I am aware I can use the click function to attach an event to the DIV element but for some reason it is not working for me. Here is how I am creating the DIV element.
function createColorSwatchDiv(color) {
var colorSwatchDiv = $("<div>");
var image = $("<img>");
image.attr("src",color.imageURL);
var label = $("<label>");
label.text(color.title);
colorSwatchDiv.append(image);
return colorSwatchDiv;
}
Then I try to attach the click event like the following:
// run a loop and build the grid layout
for(index = 0; index < colors.length; index++) {
var colorSwatchDiv = createColorSwatchDiv(colors[index]);
// attach the event
colorSwatchDiv.click(function(){
alert('hello world');
});
colorsSection.append(colorSwatchDiv);
}
// add to the dom
$("#color .imageChartOption").after(colorsSection);
But it does not work and no click event is been attached.
following is the code
var $newdiv1 = $("<div id='object1' onClick=Test()>Hello</div>");
$("body").append($newdiv1);
function Test()
{
alert("Clicked");
}
OR
$newdiv1.on('click',function(){alert("hello");});
since you have created the div in a jQuery wrapper you don't need to wrap it again here $(colorSwatchDiv).click(.... Also, are you sure that the colorSwatchDiv variable is referencing the dom element and not the in memory element? Can you apply a class or anything to the elm in the dom?

Attaching eventListener to dynamic elements in Javascript

I'm making a todo list and I have li and button tags added dynamically when adding a new list item. The button is an x which is supposed to remove the list item. I have tried several things but can't figure out how to make an eventListener for each individual x button and remove the corresponding list item when it is clicked.
The renderTodos function is where all of the dynamically added content is created. I have a data-index set to each button in which I was trying to use to access each button to attach an eventListener on each dynamic button, but I wasn't sure how to implement that. From what I have read there should be a way to do this using the currentTarget or target of the event but I don't understand how that works.
var input = document.querySelector('input[name=todoItem]'),
btnAdd = document.querySelector('button[name=add]'),
btnClear = document.querySelector('button[name=clear]'),
list = document.querySelector('.todo'),
storeList = [];
function renderTodos(){
var el = document.createElement('li'),
x = document.createElement('button');
listLength = storeList.length;
//Set text for remove button
x.innerHTML = 'x';
for(var i = 0; i < listLength; i++){
el.innerHTML = storeList[i];
list.appendChild(el);
x.setAttribute('data-index', i);
el.appendChild(x);
}
// check for correct data-index property on x button
}
function addTodos(){
storeList.push(input.value);
// Check that input is getting pushed to list array
console.log(storeList);
renderTodos();
}
function clearList(){
// make list empty
list.innerHTML = '';
storeList.splice(0, storeList.length);
//render empty list
renderTodos();
//Check that list array is empty
console.log(storeList);
}
btnAdd.addEventListener('click', addTodos);
btnClear.addEventListener('click', clearList);
Everything else on the list works so far I just can't figure out how to implement this eventListener.
One simple example can be
//a click hadler is added to #mylist which is already present in the dom
document.querySelector('#mylist').addEventListener('click', function(e) {
//assuming that the the `x` is in a span and it is the only span in the `li` we check for that, we can improve this check more to make sure we have actually clicked on the delete button
if (e.target.tagName == 'SPAN') {
//if so then since we know the structure we can delete the parent node of the target which is the span element
e.target.parentNode.parentNode.removeChild(e.target.parentNode);
}
}, false);
//kindly forgive the use of jQuery here
for (var i = 0; i < 10; i++) {
$('<li />', {
text: i
}).append('<span class="x">X</span>').appendTo('#mylist');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul id="mylist"></ul>
This is a very basic implementation of event delegation, where the actual event is bound to an ancestor element but then we use the actual event target to determine whether to act on it. We can improve the if condition to test for an class for any other attribute!!!
You can add a listener to each button using something like:
x.innerHTML = '';
x.onclick = function(){
var node = this.parentNode;
node.parentNode.removeChild(node);
};
Or you can keep the renderTodos code as it is and delegate the remove to the parent UL:
// Add the listener
list.addEventListener('click', removeItem);
// The listener function
function removeItem(event) {
var node = event.target;
// Check that the click came from an X button
// better to check against a class name though
if (node.tagName &&
node.tagName.toLowerCase() == 'button' &&
node.innerHTML == 'x') {
node = node.parentNode;
node.parentNode.removeChild(node);
}
}
basically what you want to do is add an event on the parent container and wait for the event to bubble up and identify if the event originating is from your x mark and if it is then trigger the callback function.. This is the concept I think most of the libraries use..
Or use a library like jQuery, why solve a problem that has already been solved by others.

How to append an element, all its children, and all classes of the parent and children with jQuery

I have a function that is successful in removing an element and appending it elsewhere on the page as successful. The problem is that as soon as the document is ready jQuery adds classes and attributes to the children that upon moving are lost. I need these classes and attributes to remain after removing and appending. I have thought about calling the original function that adds the classes, but the problem is they are key based and rely on their position prior to the move, calling it after changes the key and thus will add brand new and different classes.
The classes adding jQuery is pretty standard:
$(function(){
$("div").each(function(key){
if ($(this).hasClass("container")){
$(this).find("ul").addClass("parent" + key);
$(this).find(".container-item").attr("parentClass", ".parent" + key);
};
});
});
The remove/append function:
function copy_item(draggable, target){
var account = clone_items(draggable);
//$('#'+name.uid).remove();
$('#'+name.uid).hide();
target.append(make_div(name, true, true));
//$(draggable).children().attr("class", ($(draggable).children().attr("class")));
}
function make_div(name, drag, drop){
var newdiv = document.createElement('div');
newdiv.setAttribute('id', name.uid);
newdiv.appendChild(make_h3(name.username));
ul = document.createElement('ul');
ul.setAttribute("class", "domain_list");
newdiv.appendChild(ul);
for (j = 0; j < name.domains.length; ++j) {
ul.appendChild(make_li(name.domains[j], drag));
}
return newdiv;
}
The end result in the HTMl is basically:
<div class="container">
<ul class="parent0">
<li parentClass="parent0">
<li parentClass="parent0">
When recreating this structure, I need to have the class "parent0" and the parentClass attribute intact. Above you can see I've tried hiding the element, ensuring that it still stays a valid element with the correct classes/attributes, but in the end that still didn't work out. Ideally, I could remove the element entirely and recreate it with the correct classes.
If I am correct in my understanding of what you are trying to do, you do not need to .remove() and recreate the element in order to move it. You can just do this:
function copy_item(draggable, target) {
// not sure what this variable is for
// as you don't seem to be using it?
var account = clone_items(draggable);
// ...however, appending an existing
// element to another will 'move' it
// and preserve all of it's properties
target.append($('#' + name.uid));
}

Categories

Resources