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))
....
}
Related
I'm trying to create a list where the user can add their own items to it by typing in a text box and pressing the Enter key or clicking on the "Enter" button. I'm trying to get the list items to get crossed out when the user clicks on them but this doesn't seem to work on list items created by the user, it only works on list items added in the HTML file.
Shouldn't crossBTNs() work on user generated list items too? Sorry if this is a basic question, I'm new to JS.
EDIT: Figured it out
I simply did this:
li.addEventListener("click", function () {
crossOutUserItem(li); });
I added this code to createListElement(). crossOutUserItem(li) adds the class that creates the "crossed out" effect to the list item.
Original code:
var button = document.getElementById("enter");
var input = document.getElementById("userinput");
var ul = document.querySelector("ul");
function createListElement() {
var li = document.createElement("li");
li.append(document.createTextNode(input.value));
ul.appendChild(li);
input.value = "";
}
function addListAfterClick() {
if (input.value.length > 0) {
createListElement();
}
}
function addListAfterKeypress(event) {
if (input.value.length > 0 && event.keyCode === 13) {
createListElement();
}
}
function crossBTNs () {
for (let i = 0; i < ul.children.length; i++) {
ul.children[i].addEventListener("click", function() {
ul.children[i].classList.toggle("crossOut");
});
}
}
button.addEventListener("click", addListAfterClick);
input.addEventListener("keypress", addListAfterKeypress);
crossBTNs();
By adding event handlers on the li, as you have done.
function crossBTNs () {
for (let i = 0; i < ul.children.length; i++) {
ul.children[i].addEventListener("click", function() {
ul.children[i].classList.toggle("crossOut");
});
}
}
It doesn't set any event handler for the list items li which are generated dynamically, because as the js file loads the handlers are set initially only.
You will need to use event delegation in which you set the handler on the parent of li, which is ul and look for the particular child element from where the event has actually happened using e.target properties as per your requirement.
You can use this resource MDN Docs Event Delegation to know more about event delegation in javascript.
Just delegate from the closest static container - likely the UL in this case.
ul.addEventListener("click", function(e) {
const tgt = e.target.closest("li");
tgt.classList.toggle("crossOut");
});
Now you can remove all other event handling for the LI and do not need to call something after adding an LI to add event handling
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 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
I am currently working on a Todo list for practice and was wondering if there was a way to restore a list. I was thinking of creating a copy of the list and then re-adding the contents to the DOM once the user hits a restore 'Restore List' button but I just can't figure it out!
Here is my current code, the button appears when I hit 'Reset List' button but it is not functional yet.
document.addEventListener('DOMContentLoaded', () => {
//Targets the unordered list element
const list = document.getElementById("myUL");
//Targets the children of the unordered list
const li = list.children;
const resetDiv = document.getElementById('resetPanel');
const resetButton = document.createElement('button');
const restoreButton = document.createElement('button');
restoreButton.textContent = 'Restore Items';
resetButton.textContent = 'Reset List';
resetDiv.appendChild(resetButton);
//Targets the form element.
const form = document.getElementById("registrar");
//Function declaration (Begins process of creating list item)
function createListItem(text){
//Creates the list item
const li = document.createElement('li');
//Function delcaration (creates an element and returns element)
function createElement(elementName, property, value) {
const element = document.createElement(elementName);
element[property] = value;
return element;
}
//Function declaration (Adds the created element to the list)
function appendToLi(elementName, property, value){
const element = createElement(elementName, property, value);
li.appendChild(element);
return element;
}
//Appends all children to the list item.
appendToLi('span', 'textContent', text);
appendToLi('label', 'textContent', 'Completed')
.appendChild(createElement('input', 'type', 'checkbox'));
appendToLi('button', 'textContent', 'remove');
appendToLi('button', 'textContent', 'edit');
/*Returns the list item and it's children to what has called the
createListItem function*/
return li;
}
//Sets an event listener to the reset button.
resetButton.addEventListener('click', (e) => {
const ul = document.getElementById("myUL");
const listCopy = document.getElementById("myUL");
//Moves through the unordered list and removes each list item.
while (ul.firstChild) {
ul.removeChild(ul.firstChild);
}
resetDiv.appendChild(restoreButton);
});
//This button should restore the removed list items. ***********************
restoreButton.addEventListener('click', (e) => {
resetDiv.removeChild(restoreButton);
});
//Event listener (listens for click on submit button/enter press)
form.addEventListener('submit', (e) => {
e.preventDefault();
//Targets the input element.
const input = document.querySelector('input');
//If the user has not entered any text in the input field, alerts.
if(input.value === '') {
alert('Please enter an item!');
//Otherise begins the process of creating the list item.
} else {
//Holds the user text input.
const text = input.value;
/*Calls the createListItem function which will begin the process
through various other functions.*/
const listItem = createListItem(text);
list.appendChild(listItem);
input.value = '';
}
});
//Listens for clicks on the list item's children buttons.
list.addEventListener('click', (e) => {
const button = e.target;
const li = e.target.parentNode;
const ul = li.parentNode;
//Click on remove button
if(button.textContent === 'remove'){
ul.removeChild(li);
//Click on edit button
} else if (button.textContent === 'edit'){
const span = li.firstElementChild;
const input = document.createElement('input');
input.type = 'text';
input.value = span.textContent;
//Inserts a text field in place of the previous span item (User's input)
li.insertBefore(input, span);
li.removeChild(span);
button.textContent = 'save';
//Click on save button
} else if (button.textContent === 'save'){
const span = document.createElement('span');
const input = li.firstElementChild;
span.textContent = input.value;
//Inserts the new text over the input field.
li.insertBefore(span, input);
li.removeChild(input);
button.textContent = 'edit';
}
});
});
Looking at what you wanna do u obviously have to save deleted items into a cache but copying d whole thing wont be efficient (it would work maybe with a bit more code) try placing d deleted item into an array list with d position iD on d initial list and putting d item back u could just put it back at the initial position and if d id is a numbering system that helps with position you could just add 1 to all d items after d previously deleted item