Evening folks.
Trying to wrap up my to do list and I'm not able to remove items from localStorage without either deleting everything from using the wrong key or the contents just re-appearing on page refresh. A second smaller issue is that button text is merging into the innerText, like it's supposed to, but I can't find a way to exclude it It is currently commented out, if I don't then it breaks the previous entry. I've left my most recent, and rather poor attempt, below but otherwise, the rest appears to be working.
Not sure if it's ok to attach the whole code, but here it is below.
const todoForm = document.querySelector('#todoForm');
const todoList = document.querySelector('#todoList');
let todoItem = document.querySelector('#todoItem');
// const todo = JSON.parse(localStorage.getItem('todo'));
// Pull from storage
const savedList = JSON.parse(localStorage.getItem('todo')) || [];
for (let i = 0; i < savedList.length; i++) {
const newTodo = document.createElement('li');
newTodo.innerText = savedList[i].item;
const newButton = document.createElement('button');
let itemId = { id: new Date().getTime() };
// newButton.innerText = 'Remove';
newButton.setAttribute('id', itemId.id);
newTodo.isCompleted = savedList[i].isCompleted ? true : false;
if(newTodo.isCompleted) {
newTodo.style.textDecoration = 'line-through';
}
todoList.appendChild(newTodo);
newTodo.appendChild(newButton);
}
// Add Item and Remove Button
todoForm.addEventListener('submit', function(e){
e.preventDefault();
const newTodo = document.createElement('li');
const newItem = document.querySelector('#todoItem').value;
const newButton = document.createElement('button');
let itemId = { id: new Date().getTime() };
// newButton.innerText = 'Remove';
newButton.setAttribute('id', itemId.id);
newTodo.innerText = newItem;
newTodo.setAttribute('id', itemId.id);
newTodo.isCompleted = false;
todoList.appendChild(newTodo);
newTodo.appendChild(newButton);
todoForm.reset();
// Save to storage
savedList.push({ item: newTodo.innerText, isCompleted: false, id: new Date().getTime() });
localStorage.setItem('todo', JSON.stringify(savedList));
});
// Strike Through Item
todoList.addEventListener('click', function(e){
let clickListItem = e.target;
if (!clickListItem.isCompleted){
clickListItem.style.textDecoration = 'line-through';
clickListItem.isCompleted = true;
} else {
clickListItem.style.textDecoration = 'none';
clickListItem.isCompleted = false;
}
for (let i = 0; i < savedList.length; i++) {
if (savedList[i].item === clickListItem.innerText) {
savedList[i].isCompleted = !savedList[i].isCompleted;
localStorage.setItem('todo', JSON.stringify(savedList));
}
}
});
// Remove from storage
todoList.addEventListener('click', function(e){
let removeItem = e.target;
const taskId = e.target.id;
if (e.target.tagName === 'BUTTON'){
e.target.parentNode.remove();
removeFunc(taskId);
}
});
function removeFunc(taskId){
for (let i = 0; i < savedList.length; i++){
const key = savedList[i].id;
if(key === taskId.id){
localStorage.removeItem(key);
localStorage.setItem('todo', JSON.stringify(savedList));
}
}
}
Thanks for any insight.
My first guess looking at this would be the that, since the IDs are being defined by Date.getTime() being called at two different times, that those IDs are not the same. I would suggest that, when you push to savedList at the end of the function to add an item, that you set id as newItem.id, like you for the item name, rather than calling getTime() again
I do see few problems in your code. Here we go.
Remove text reappears because on adding an item, you create todo object with item value set to newTodo.innerText, if you check your saved value in the localstorage it holds extra Remove in it, that's because innerText gets the text of elements under newTodo (in our case we have a button in there). As a fix, you just need to set the actual value from the textbox and not the innerText. You already have that stored in a variable called newItem
And yes, as like #cfinn16 pointed it out, the id we save here would be in number format, when you compare the id from remove button attribute with the id from the savedList array you will see a mismatch. As a resolution, you can convert getTime().toString().
savedList.push({ item: newTodo.innerText, isCompleted: false, id: new Date().getTime() });
Deleting an item, not actually removing the item from both in-memory array i.e savedList or from the localStorage. All we want to do it, just get the taskId, filter/remove items from savedList then replace it in the localStorage with same key. But on loading each todoItems on page refresh, you set new date as the value to each todoItems but that should be the value from the localstorage itself.
let itemId = { id: new Date().getTime() };
Strikethrough an item, has a similar problem. Here you are trying to find clicked item from the array using text instead we can use the id itself.
for (let i = 0; i < savedList.length; i++) {
if (savedList[i].item === clickListItem.innerText) {
savedList[i].isCompleted = !savedList[i].isCompleted;
localStorage.setItem('todo', JSON.stringify(savedList));
}
}
Solution:
https://codepen.io/renishb10/project/editor/ANyqqo
Let me know if you've any questions.
With the help from Renish, I've modified to include the follow and posting it here so it may help anyone else.
// Save to storage
savedList.push({ item: newItem, isCompleted: false, id: new Date().getTime().toString() });
localStorage.setItem('todo', JSON.stringify(savedList));
Changed the new Date() to a string. As both Renish and cfinn pointed out I had mismatch .id. Changing newTodo to newItem go around my innerText from the button being carried over.
// Pull from Storage
newButton.innerText = 'Remove';
newButton.setAttribute('id', savedList[i].id);
Modified my pull from storage code to reflect the new button .id.
function removeFunc(taskId){
splicedList = savedList.filter(l => l.id != taskId)
localStorage.setItem('todo', JSON.stringify(splicedList));
}
Used a filter instead to find the items to remove, based on the .id.
Github of the full modified code:
https://github.com/BreadsticksN7/collections/blob/20b679fc704d05af5576faa3963f676c0bd2665e/todolist.js
Thanks to everyone and their assistance.
Related
I have a web page that returns a list of objects like:
date.pdf
names.csv
address.pdf
age.csv
cost.csv
budget.csv
data.pdf
race.pdf
contractors.csv
When a user checks budget.csv, I want every object with the .csv extension from that point to be pushed into csv_files[]. If they select names.csv, then every .csv including and after names is pushed into the array.
So the only data that gets pushed into the array is from the selected object downwards. How can I implement this?
Current code
const csv_files = []
$scope.listAllobjects = (err, data) => {
$.each(data.Contents, (index, value) => {
if (value.Key.endsWith("csv")) {
csv_files = [];
}
// Handle click on selection checkbox
$("#filesobjects-table tbody").on("click", 'input[type="checkbox"]', (e1) => {
const checkbox = e1.currentTarget;
const $row = $(checkbox).closest("tr");
const data = $tb.DataTable().row($row).data();
let index = -1;
// Prevent click event from propagating to parent
e1.stopPropagation();
// Find matching key in currently checked rows
index = $scope.view.keys_selected.findIndex((e2) => e2.Key === data.Key);
if (checkbox.checked && data.Key.endsWith("csv")) {
console.log(selected csv)
}
});
}
There's a few ways, I suppose, to approach this problem, but the most intuitive to me is this:
const csvList = ["date.pdf","names.csv","address.pdf","age.csv","cost.csv","budget.csv","data.pdf","race.pdf","contractors.csv"];
const selectedCsv = 'budget.csv';
function getCsvsAfter(csvList, selectedCsv) {
const filteredCsvs = [];
let found = false;
for (let csv of csvList) {
if (csv === selectedCsv) found = true;
if (found) filteredCsvs.push(csv);
}
return filteredCsvs;
}
console.log(getCsvsAfter(csvList, selectedCsv));
Iterate over every csv, and when you've hit the one you're trying to match, set a variable called found to true. Once it's true, you can add every following csv onto the list.
const list = ['date.pdf','names.csv','address.pdf','age.csv','cost.csv','budget.csv','data.pdf','race.pdf','contractors.csv'];
const selected = 'budget.csv'
const csv_files = list.slice(list.indexOf(selected))
console.log(csv_files)
Here you go with a pure JavaScript solution (Descriptive comments has been added in the below code snippet).
var contentData = ["date.pdf", "names.csv", "address.pdf", "age.csv", "cost.csv", "budget.csv", "data.pdf", "race.pdf", "contractors.csv"];
var myDiv = document.getElementById("cboxes");
for (var i = 0; i < contentData.length; i++) {
var checkBox = document.createElement("input");
var label = document.createElement("label");
checkBox.type = "checkbox";
checkBox.value = contentData[i];
myDiv.appendChild(checkBox);
myDiv.appendChild(label);
label.appendChild(document.createTextNode(contentData[i]));
}
// Event to handle the checkbox click
document.getElementById('getResult').addEventListener('click', () => {
document.getElementById('showResult').innerHTML = getCheckedValues();
});
function getCheckedValues() {
// filtered out the checked items.
const element = Array.from(document.querySelectorAll('input[type="checkbox"]'))
.filter((checkbox) => checkbox.checked).map((checkbox) => checkbox.value);
// element[0] will always return the first checked element and then we are getting index of that.
const checkedElemIndex = contentData.indexOf(element[0]);
// Slice the content data to get the elements from the checked element index.
return contentData.slice(checkedElemIndex, contentData.length)
}
<div id="cboxes"></div>
<button id="getResult">Get Result</button>
<pre id="showResult"></pre>
I am practicing blog stuff. posting and deleting posts. mini social media I can say. And I wanted to save posts on localStorge. however I could save only 1 post at a time. and then I wanted to do it with IDs.
I create id with random number generator:
let newId = Math.floor(Math.random() * (1000000 - 100000) + 100000)
let postContents = {
ID : newId,
text: value,
}
an then I upload those values in let storedPosts = [] array.
then I save it to local storage with JSON:
let toJson = () => {
localStorage.setItem('storedPosts', JSON.stringify(storedPosts));
}
and then I get it from Local Storage:
let storedJsonPosts = localStorage.getItem('storedPosts')
let storedPosts_toUpload = JSON.parse(storedJsonPosts)
and then I join these two arrays together:
let storedPostsArray = storedPosts.concat(storedPosts_toUpload)
and after this I don't know what to do. I tried this:
let uploadStoredPosts = () => {
for (let i = 0; i < storedPostsArray.length; i++) {
let post = document.createElement('div')
$post_place.appendChild(post)
let text = document.createElement('p')
post.appendChild(text)
text.textContent = storedPostsArray[i].text
}
}
but it showed this:
It couldn't reach array values. plz help
Is this something that you're after?
The code reads from localStorage, parses that information, returns an empty array if it's the first time the user posted, pushes a new value to the array, stores that array by stringifying it, and the appending the new value to the document.
If you want the page to read from localStorage on page load, you need to add a function that reads from localStorage, and then loops through all posts to add each one of them by using appendToDocument().
StackOverflow doesn't allow the use of localStorage, so I used a variable for demo purposes.
I left out id as a property. You can play around with that by yourself, but I would suggest to use a timestamp as a foreign key ("id").
var justForDemoPurpose = null;
const addPostBtn = document.getElementById("add-button");
const addPostInput = document.getElementById("add-post");
const postContainerEl = document.getElementById("post-container");
addPostBtn.addEventListener('click', addPost);
function readFromLocalStorage(key) {
let localStorageItem = JSON.parse(justForDemoPurpose);
// let localStorageItem = JSON.parse(localStorage.getItem(key));
console.log('returning items:', localStorageItem);
return localStorageItem;
}
function storeInLocalStorage(key, value) {
justForDemoPurpose = JSON.stringify(value);
// JSON.stringify(localStorage.setItem(key, value));
}
function addPost() {
let postValue = addPostInput.value;
if (postValue) {
const LOCAL_STORAGE_KEY = 'posts';
let storedPosts = readFromLocalStorage(LOCAL_STORAGE_KEY) || [];
storedPosts.push(postValue);
storeInLocalStorage(LOCAL_STORAGE_KEY, storedPosts);
appendToDocument(postValue);
}
}
function appendToDocument(postValue) {
let divEl = document.createElement('div')
divEl.textContent = postValue;
postContainerEl.appendChild(divEl);
}
<div class="addPostContainer">
<input id="add-post" placeholder="Type here"> <button id="add-button">Add Post</button>
</div>
<section id="post-container"></section>
I'm having a problem removing an item from a "cart". Each time i'm clicking on delete, it's deleting the right element from the DOM, but it's always deleting the first element from my array/localStorage. I know the problem is in my splice method, but i have literally no idea about what to do.
If more informations are required, i can provide the github it's located on
Thanks in advance
let cartItms = JSON.parse(localStorage.getItem("Cart"));
let productId = JSON.parse(localStorage.getItem("productId"));
let optionSelected = JSON.parse(localStorage.getItem('Lense'));
let totalPrice = 0;
const shoppingCart = document.querySelector('.cart__content--items');
function deleteProduct() {
shoppingCart.addEventListener('click', (e) => {
e.preventDefault();
//Remove item from cart
if(e.target.classList[0] === "cart__content--item__delete") {
e.target.parentElement.parentElement.remove();
cartItms.splice(e.target,1);
productId.splice(e.target,1);
optionSelected.splice(e.target,1);
localStorage.setItem('Cart', JSON.stringify(cartItms));
localStorage.setItem('productId', JSON.stringify(productId));
localStorage.setItem('Lense', JSON.stringify(optionSelected));
}
//Recalculate the price of current cart
totalPrice = 0;
cartItms.forEach((data) => {
totalPrice += data.price/100;
})
document.querySelector('.cart-content').innerHTML = '('+ cartItms.length +')';
document.querySelector('.total-price').innerHTML = totalPrice + "€";
})
}
Assuming cartItms is an array, then you can use.
cartItms.shift();
The shift() method removes the first element from an array and returns
that removed element. This method changes the length of the array.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift
so basically i want to make a phone contacts app, and i try to save the saved contact to local storage
so this is the function when the save button clicked
saveContact(name, number){
//To check if the name input or phone input is not blank
if(nameInput.value == '' || phoneInput.value == ''){
info.style.display = 'block'
}
const firstLetter = name[0].toUpperCase()
const getContact = localStorage.getItem(firstLetter)
const storedObject = {
[name]:number
}
//If contact's first letter exists in localstorage
if (getContact){
const oldData = [JSON.parse(localStorage.getItem(firstLetter))]
oldData.push([storedObject])
const oldDataString = JSON.stringify(oldData)
localStorage.setItem(firstLetter, oldDataString)
const finalOldData = []
//i do a looping here to push each contact's object to a new array which is finalOldData
//but it doesn't work well. it doesn't actually add a new object to the array instead of replacing the old object with a new one
oldData.forEach(e => {
finalOldData.push(e[0])
})
const finalOldDataString = JSON.stringify(finalOldData)
localStorage.setItem(firstLetter, finalOldDataString)
}
//If contact's first letter doesn't exist in localstorage
else{
const storedObjectString = JSON.stringify([storedObject])
localStorage.setItem(firstLetter, storedObjectString)
this.clearSave()
}
}
so the issue is when i try to add a contact which its first letter exist in local storage and make it as a list
//and this is the result i want
Storage
A: "[{\"amber\":\"1242134\"},{\"annie\":\"123421\"}]"
length: 1
You can consider the code below, it is working as expected.
Changes
const oldData = [JSON.parse(localStorage.getItem(firstLetter))]
No need to put the result from JSON.parse into an array, it already is an array and also you can use the variable getContact instead of calling getItem again on localStorage.
oldData.push([storedObject])
No need to push an array into oldData, simply push storedObject.
I've removed the initial check for making testing easy, you can add it back.
function saveContact(name, number) {
if (!name || !number) {
return;
}
const firstLetter = name[0].toUpperCase();
const getContact = localStorage.getItem(firstLetter);
const storedObject = { [name]: number };
if (getContact) {
const oldData = JSON.parse(getContact);
oldData.push(storedObject);
const oldDataString = JSON.stringify(oldData);
localStorage.setItem(firstLetter, oldDataString);
} else {
const storedObjectString = JSON.stringify([storedObject]);
localStorage.setItem(firstLetter, storedObjectString);
}
}
i have 5 items in my page with 3 information. (for example, name and price and number )
i want when i click on them (for example item 1) for first time, create an object and save items information to localStorage and for another times increase the number of item in localstorage.
function() {
items.forEach(function(btn) {
btn.addEventListener('click', function(event) {
let exist = localStorage.getItem('name');
var name =
event.target.parentElement.parentElement.parentElement.parentElement.children[1].children[0].textContent;
localStorage.setItem('name', name);
var price =
event.target.parentElement.parentElement.parentElement.parentElement.children[1].children[2].textContent;
localStorage.setItem('price', price);
var number = localStorage.getItem('number');
number = parseInt(number);
if (number) {
localStorage.setItem('number', number + 1);
} else {
localStorage.setItem('number', 1)
}
});
});
})();
its my code, but when i click on any item, previeos details in localstorage will be lost and information of new item replaced.
how i can resolve it?
When you are calling localStorage.setItem('name', name) you are overwriting the previous value of name. To store all names, prices, and numbers you have to use array. But, localStorage supports nothing but string. So before writing, you have to convert the array to a string, and upon reading you have to revert the string back to an array.
function() {
items.forEach(function(btn) {
btn.addEventListener('click', function(event) {
let names = localStorage.getItem('name');
const exists = !!names;
names = exists ? JSON.parse(names) : [];
let prices = exists ? JSON.parse(localStorage.getItem('price')): [];
let numbers = exists ? JSON.parse(localStorage.getItem('number')) : [];
var name =
event.target.parentElement.parentElement.parentElement.parentElement.children[1].children[0].textContent;
const nI = names.indexOf(name);
if (nI === -1) {
names.push(name);
localStorage.setItem('name', JSON.stringify(names));
var price =
event.target.parentElement.parentElement.parentElement.parentElement.children[1].children[2].textContent;
prices.push(price);
localStorage.setItem('price', JSON.stringify(prices));
numbers.push(1);
} else {
// else they are already in localStorage, just increase number
numbers[nI]++;
}
localStorage.setItem('number', JSON.stringify(numbers));
});
});
})();