I am trying to make a To-Do List. When I am trying to remove the I am not able to do it at all. I don't know how to run function removeBtn()
var input = document.getElementById("task");
var button = document.getElementById("enter");
var ul = document.querySelector("ul");
function newElement(){
var node = document.createElement("li");
node.appendChild(document.createTextNode(input.value));
var delButton = document.createElement("button");
delButton.innerHTML = 'Done';
node.appendChild(delButton);
delButton.addEventListener('click', removeBtn);
ul.appendChild(node).classList.add("remList");
input.value ='';
}
function checkLength(){
if (input.value.length != 0){
newElement();
}
else {
alert('Empty');
}
}
function removeBtn(){
var list = document.getElementsByClassName("remList");
ul.removeChild("remList");
}
button.addEventListener("click", checkLength);
In addition to selecting a single element to remove, you need to tie the correct .remList to be removed with the button listener. If you want the created node to be removed when the delButton is clicked, you need to connect node to the listener somehow. One option is:
// ...
node.appendChild(delButton);
delButton.addEventListener('click', () => node.remove());
ul.appendChild(node).classList.add("remList");
// ...
(no need for a separate removeBtn function at all)
document.getElementsByClassName() returns a NodeList collection of elements. If you want to remove an individual one, you can access the collection like an array:
var list = document.getElementsByClassName("remList");
ul.removeChild(list[0]); // Remove the first `.remList` child
Related
I am facing a bit of trouble here. I am trying to create a to-do list with local storage but the only things I got to work are adding list item it to the local storage and deleting all items from the local storage but I can't delete a single SELECTED item out from the list. Can someone help me figure:
1) Removing a selected single item from the list.
2) Putting Checkbox before the List Text.
3) On clicking checkbox, toggle class list "strike" and remembering it on load/page refresh.
Here is my code:
<body>
<div>
<h1>To-do's list</h1>
<div>
<input type="text" id="textBox">
<button id="enterBtn" type="button">Enter</button>
<div>
<uL id="ul">
<li class="li"><input type="checkbox" class="checkBox" name=""> Buy food for Siboo <button class="deleteBtn">Delete</button></li>
<li class="li"><input type="checkbox" class="checkBox" name=""> Get a new controller <button class="deleteBtn">Delete</button></li>
</uL><br>
<button id="deleteAllBtn"><i class="fa fa-trash"></i> Delete All Items</button>
</div>
<script type="text/javascript" src="script.js"></script>
</div>
</body>
Here is CSS:
.strike {
text-decoration: line-through;
}
Here is my JS:
var textBox = document.getElementById("textBox");
var enterBtn = document.getElementById("enterBtn");
var ul = document.querySelector("ul");
var li = document.getElementsByClassName("li");
var checkBox = document.getElementsByClassName("checkBox");
var deleteBtn = document.getElementsByClassName("deleteBtn");
var deleteAllBtn = document.getElementById("deleteAllBtn");
var itemsArray = localStorage.getItem('items') ? JSON.parse(localStorage.getItem('items')) : [];
localStorage.setItem('items', JSON.stringify(itemsArray));
var data = JSON.parse(localStorage.getItem('items'));
// Functions *********************
// Adding New Items to List - adding list element with checkbox and delete button *********************
function addNewItemToList(text)
{
itemsArray.push(textBox.value);
localStorage.setItem('items', JSON.stringify(itemsArray));
liMaker(textBox.value);
}
function liMaker(text) {
var newLi = document.createElement("li");
newLi.textContent = text;
newLi.className = "li";
ul.appendChild(newLi);
var createCheckBox = document.createElement("input");
createCheckBox.type = "checkbox";
createCheckBox.className = "checkBox";
newLi.appendChild(createCheckBox);
var createDeleteButton = document.createElement("button");
var nameButtonDelete = document.createTextNode("Delete");
createDeleteButton.appendChild(nameButtonDelete);
createDeleteButton.className = "deleteBtn";
newLi.appendChild(createDeleteButton);
}
data.forEach(item => {
liMaker(item);
});
// CheckBox ELEMENT - click on checkBox to strike the list item off list*********************
function checkBoxFunction() {
for (var i = 0; i < checkBox.length; i++) {
checkBox[i].onclick = function () {
this.parentNode.classList.toggle("strike");
}}
}
// // DELETE BUTTON - click the delete button to delete the list item *********************
function deleteBtnFunction() {
for (var i = 0; i < deleteBtn.length; i++) {
deleteBtn[i].onclick = function () {
this.parentNode.parentNode.removeChild(this.parentNode);
}}
}
// DELETE ALL BUTTON - click the Delete ALl Items button to remove all items from the list *********************
function deleteAllBtnFunction()
{
localStorage.clear();
while (ul.firstChild) {
ul.removeChild(ul.firstChild);
}
itemsArray = [];
}
// TEXTBOX - press enter key to add an item to list *********************
function textBoxFunction()
{
if (event.keyCode === 13 && textBox.value.length > 0)
{
addNewItemToList();
textBox.value = "";
}
else if (event.keyCode === 13)
{
alert("Please enter an item to-do!");
}
}
// ENTER BUTTON - click the enter button to add item to list *********************
function enterBtnFunction()
{
if (textBox.value.length > 0)
{
addNewItemToList();
textBox.value = "";
}
else
{
alert("Please enter an item to-do!");
}
}
listItemFunction();
deleteBtnFunction();
// Event Listeners *********************
textBox.addEventListener("keypress", textBoxFunction);
enterBtn.addEventListener("click", enterBtnFunction);
deleteAllBtn.addEventListener("click", deleteAllBtnFunction);
// End of Event Listeners *********************
localStorage.removeItem(/*key*/);
You can use this function to remove a specific item and save the items to localstorage again:
function removeItem(text) {
var items = JSON.parse(localStorage.getItem("items"));
items = items.filter(function(e) {return e !== text; });
localStorage.setItem("items", JSON.stringify(items));
}
removeItem("itemname");
I am not a professional but recently I created a todo app like this. I figured out after adding a new item, action listeners do not count them. So I inserted the event listeners inside the new element creation function after adding the element to the DOM.
Here is my suggestion
First, you have to link jQuery-3.2.1.slim.min.js to your project
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
Put this code to the end of your liMaker function.
$('input[type="checkbox"]').click(function() {
if ($(this).is(':checked')) {
//Call your function
console.log(this.id)
}
});
When creating the list element give each of them a unique id (add it to your checkbox). Maybe you can give them the array index.
createCheckBox.id ={unique id}
After doing that when you click the checkbox to invoke the above function. In that function this.id is the unique value you gave to the checkbox.
Then you can use it to remove that index from your array.
Second Method (Pure JS)
Give a common class name to all checkboxes and a unique id also.
const checkBoxes = document.querySelectorAll(".{common_class_name}")
for(const cb of checkBoxes){
button.addEventListener('click',function(){
let id = this.id
/*this id is the value you gave to the checkbox.
Call your deleting methods here*/
})
}
Place this method at the end of your element creation method. This must run every time you add an element.
I copied your code and my method is working fine. I am a beginner there may be better ways to do that. but my method works.
Good Luck
how to download an element created by the user and give it an event?
function tasks(e) {
inputV = input.value;
e.preventDefault();
if (inputV !== "") {
const ul = document.querySelector('.tasks-list');
let li = document.createElement('li');
li.innerHTML += inputV /*`<button class="deleteTasks">Usuń</button>`*/;
ul.appendChild(li);
let btnDell = document.createElement('button');
btnDell.setAttribute("id", "deleteTasks");
btnDell.innerHTML += 'usuń';
li.appendChild(btnDell);
input.value = "";
}
};
add.addEventListener('click', tasks);
If I get it well you want your btnDell to delete the li element. You should use something like on the button click
function removeParent(e){
e.parentNode.remove();
}
After creation of new list Element, you can attach your custom event handler.
function tasks(e) {
inputV = input.value;
e.preventDefault();
if (inputV !== "") {
const ul = document.querySelector('.tasks-list');
let li = document.createElement('li');
li.innerHTML += inputV /*`<button class="deleteTasks">Usuń</button>`*/;
let node = ul.appendChild(li).cloneNode(true);
node.addEventListener('click',(e)=>{
e.preventDefault();
let target = e.target;
// put your logic here to execut on target after it being clicked
},false);
let btnDell = document.createElement('button');
btnDell.setAttribute("id", "deleteTasks");
btnDell.innerHTML += 'usuń';
li.appendChild(btnDell);
input.value = "";
}
};
add.addEventListener('click', tasks);
Edit I am editing this after reading your comment, please edit your question instead of put a comment to clarify your question. My assumption was that you want this functionality.
But it seems you'r logic on delete don't get execute on newly created items, if that's the case try to set a class property on each deletable li and write btnDell base on querySelectorAll that get all the elements at the time it's getting execute.
I'm trying to remove an item from local storage. It works except it occasionally removes more than one item.
I have tried array.splice removing local storage then resetting it with the new values and haven't found a way to fix it, I'm sure it's something simple.
let itemsArray = JSON.parse(localStorage.getItem("itemsArray")) || [];
//Initialize Function
window.addEventListener("load", () => showItems(itemsArray));
//Add event listener for the form submit
myForm.addEventListener("submit", onSubmit);
//Add event listener for the click event on the delete button
itemList.addEventListener("click", removeItem);
function showItems(itemsArray) {
itemList.innerHTML = itemsArray.join("");
}
//Place the input into to list of items
function onSubmit(e) {
//Prevent the form submission
e.preventDefault();
//Create li element for the DOM
li = document.createElement("li");
//Place input value into li
li.appendChild(document.createTextNode(`${item.value}`));
//Create the delete button and place it to the right of input value
const btnDelete = document.createElement("button");
btnDelete.classList.add("btnDelete");
btnDelete.appendChild(document.createTextNode("X"));
li.appendChild(btnDelete);
itemList.appendChild(li);
itemsArray.push(li.outerHTML);
localStorage.setItem("itemsArray", JSON.stringify(itemsArray));
//Reset input value to empty
item.value = "";
}
//Delete item
function removeItem(e) {
if (e.target.classList.contains("btnDelete")) {
if (confirm("Are You Sure You Want To Delete This Item?")) {
removeLocalStorage();
let li = e.target.parentElement;
itemList.removeChild(li);
}
}
}
function removeLocalStorage(){
let store = JSON.parse(localStorage.getItem("itemsArray")) || [];
for(let i = 0; i < store.length; i++){
store.splice(i, 1);
localStorage.setItem('itemsArray', JSON.stringify(store));
}
}
All I want is to remove the item that corresponds to the item being deleted from the UI. When I delete, say index 1, it removes every other index.
This is essentially the Brad Traversy project on DOM manipulation. I am trying to work more with local storage for other projects.
You need to pass the index of the item you want deleted to the removeLocalStorage function. See code below:
//Delete item
function removeItem(e) {
if (e.target.classList.contains("btnDelete")) {
if (confirm("Are You Sure You Want To Delete This Item?")) {
let li = e.target.parentElement;
let index = Array.prototype.indexOf.call(itemList.children, li);
removeLocalStorage(index);
itemList.removeChild(li);
}
}
}
function removeLocalStorage(index){
let store = JSON.parse(localStorage.getItem("itemsArray")) || [];
store.splice(index, 1);
localStorage.setItem('itemsArray', JSON.stringify(store));
}
Did you try the line?:
window.localStorage.removeItem('itemsArray');
This line will delete only the item with specific key in the localstorage.
It seems to me that with the loop you are removing the entire array. You have to pass an identifier to removeFromLocalStorage(). There you have to know what element you want to remove. The loop only make sense to me if you want to discover the index of an particular element with some property. For example:
...
if (
confirm("Are You Sure You Want To Delete This Item?")
) {
removeLocalStorage(e.target.id);
let li = e.target.parentElement; itemList.removeChild(li);
}
removeFromLocalStorage(identifier){
...
let id
store.forEach((el,index)=> {
id = el.identifier === identifier && index
}).
store.splice(id,1)
localStorage.setItem('itemArray', JSON.stringify(store))
....
}
I want to add an event listener to the checkbox that is created within an <li>
When the event is triggered I want to check if it is checked or unchecked
From my understanding the event for a checkbox is "onChange" and the property is "checked" but my solution is not working.
Can someone please explain to me why this solution does not work?
New to JavaScript so please explain in the most simple way.
JavaScript only please
Thank you in advance
HTML
<body>
<div class="wrapper">
<ul id="taskList">
</ul>
<div id="add-task-area">
<input type="text" id="addTaskInput" value="">
<button id="addTaskButton">Add Task</button>
</div>
</div>
</body>
JAVASCRIPT
let taskList = document.querySelector("#taskList");
const addTaskInput = document.querySelector("#addTaskInput");
const addTaskButton = document.querySelector("#addTaskButton");
const addTask = () => {
if (addTaskInput.value != " ") {
let taskItem = document.createElement("li");
let taskText = document.createElement("span");
taskText.textContent = addTaskInput.value;
let checkBox = document.createElement("input");
checkBox.setAttribute("type", "checkBox");
checkBox.setAttribute("class", "checkbox");
let removeItem = document.createElement("button");
removeItem.setAttribute("class", "remove");
removeItem.textContent = "Delete";
taskList.appendChild(taskItem);
taskItem.appendChild(taskText);
taskItem.appendChild(checkBox);
taskItem.appendChild(removeItem);
addTaskInput.value = " ";
};
}
addTaskButton.addEventListener("click", addTask);
addTaskInput.addEventListener("keydown", (event) => {
if (event.keyCode == 13) {
addTask();
}});
let checkbox = document.querySelectorAll(".checkbox")
checkbox.addEventListener("onChange", test);
const test = () => {
if (checkbox.checked) {
alert("checked");
} else {
alert ("unchecked")
}
}
I am working on the same problem and managed to get it figured out!
You can bind event handlers to dynamically created elements the same way you assign an id to them, such as by doing 'li.onclick = checkCount;', where checkCount is the name of the function you want to assign to the handler.
After a lot of time and effort, I created a function that checks the state of checkboxes, pushes the number that are checked to an array, and returns the length of the array(aka the dynamically clicked checkboxes) within a span tag.
When you add the event listener to the checkbox, it is important to state that the other function is false, or else the binding will not work. I have attached my code below, I hope it is helpful to you.
const list = document.getElementById("todo-list");
//creates new li and checkboxes
function newTodo(evt) {
//stops page from reloading every time
evt.preventDefault();
const input = document.getElementById("todo-text").value;
const li = document.createElement("li");
li.appendChild(document.createTextNode("- " + input));
list.appendChild(li);
document.getElementById("todo-text").value = "";
var checkbox = document.createElement('input');
checkbox.type= "checkbox";
checkbox.value = 1;
checkbox.class = "todo";
li.appendChild(checkbox);
li.onclick = checkCount;
}
// binds event listener to call first function
const form = document.getElementById("btn").addEventListener('click', newTodo);
//specifies this will call only 2nd function since 1st function has finished
check = document.getElementsByClassName('todo');
for (var i = 0; i < check.length; i++) {
check[i].addEventListener('click', newTodo, false);
}
const checkCount = function () {
var selected = [];
var span = document.getElementById('item-count');
var checkboxes = document.querySelectorAll('input[type=checkbox]:checked');
for (var i = 0; i < checkboxes.length; i++) {
selected.push(checkboxes[i]);
}
span.innerHTML = selected.length;
};
It doesn't work because the checkbox doesn't exist by the time you are adding the event listener: checkbox.addEventListener("onChange", test).
You can try adding the event listener right after you create the checkbox:
...
var checkbox = document.createElement('input');
checkbox.addEventListener("onChange", test) // <-- add this line
checkbox.type= "checkbox";
...
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);
}