I am doing a task list with an editable function for the each task item. What I expect is that when I update item's value, the value in LocalStorage update simultaneously. Currently, the value in LocalStorage can be updated, however, it only updates the last value of it no matter which item's value I modify. And the one should be changed does not be modified. How do I change correct localStorage value when I revise the task item?
const todo__input = document.querySelector(".todo__input")
const add__btn = document.querySelector(".add__btn")
const item__sector = document.querySelector(".item__sector")
function createToDoItem(toDoItem) {
const position = "beforeend"
const item = `
<div class="item">
<input type="checkbox" class="done__btn">
<input type="text" class="item__content" value="${toDoItem}" disabled>
<button class="edit__btn"><i class="far fa-edit"></i></button>
<button class="delete__btn"><i class="far fa-trash-alt"></i></button>
</div>
`
item__sector.insertAdjacentHTML(position, item)
return item__sector
}
// load todo item from localstorage when page is loaded
document.addEventListener("DOMContentLoaded", getLocalStorage)
// add item to the item sector
add__btn.addEventListener("click", e => {
e.preventDefault()
const input__value = todo__input.value
if (input__value.trim() === "") { return }
createToDoItem(input__value)
saveLocalStorage(input__value)
todo__input.value = ""
})
// keypress Enter
document.addEventListener("keypress", e => {
if (e.keyCode == 13) {
e.preventDefault()
const input__value = todo__input.value
if (input__value.trim() === "") { return }
createToDoItem(input__value)
saveLocalStorage(input__value)
todo__input.value = ""
}
})
// the function on item (done, edit, and delete)
item__sector.addEventListener("click", e => {
const parent = e.target.parentElement
// done
if (e.target.classList.contains("done__btn")) {
e.target.nextElementSibling.classList.toggle("done__color")
}
// edit the todo item
if (e.target.classList.contains("edit__btn")) {
if (e.target.previousElementSibling.disabled.disabled == true) {
e.target.previousElementSibling.disabled = !e.target.previousElementSibling.disabled
} else {
e.target.previousElementSibling.disabled = !e.target.previousElementSibling.disabled
e.target.previousElementSibling.setAttribute("value", e.target.previousElementSibling.value)
editLocalStorage(e.target.previousElementSibling)
}
}
// delete todo item
if (e.target.classList.contains("delete__btn")) {
parent.remove()
deleteLocalStorage(e.target.previousElementSibling.previousElementSibling)
}
})
// function for check todo status in the LocalStorage
function checkLocalStorage() {
let todos
if (localStorage.getItem("todos") === null) {
todos = []
} else {
todos = JSON.parse(localStorage.getItem("todos"))
}
return todos
}
// function for save localstorage
function saveLocalStorage(todo) {
const todos = checkLocalStorage()
todos.push(todo)
localStorage.setItem("todos", JSON.stringify(todos))
}
// function for get item and render to the screen from localstorage
function getLocalStorage() {
const todos = checkLocalStorage()
todos.forEach(todo => {
createToDoItem(todo)
})
}
// edit localStorage
function editLocalStorage(todo) {
const todos = checkLocalStorage()
const todoIndex = todo.getAttribute("value")
todos.splice(todos.indexOf(todoIndex), 1, todoIndex)
localStorage.setItem("todos", JSON.stringify(todos))
}
====
<body>
<div class="container">
<h1 class="title">My To-Do List</h1>
<form class="add__todo">
<input type="text" class="todo__input" placeholder="Add a task...">
<button class="add__btn">Add</button>
</form>
<div class="item__sector">
</div>
<div class="item__status">
<button class="all">All</button>
<button class="completed">COMPLETE</button>
<button class="incompleted">UNCOMPLETE</button>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>
<script src="app.js"></script>
</body>
The reason that causes your solution to edit the last value is:-
The todoIndex variable inside the editLocalStorage function is referencing the new updated value from your input which is not yet stored inside the todos array in local storage therefore indexOf() returns -1 hence editing the last value.
I have rewritten the JS with a tweak to the functions item__sector.addEventListener, editLocalStorage and added a global variable edit__index
Code Snippet
const todo__input = document.querySelector(".todo__input")
const add__btn = document.querySelector(".add__btn")
const item__sector = document.querySelector(".item__sector")
let edit__index = -1
function createToDoItem(toDoItem) {
const position = "beforeend"
const item = `
<div class="item">
<input type="checkbox" class="done__btn">
<input type="text" class="item__content" value="${toDoItem}" disabled>
<button class="edit__btn"><i class="far fa-edit"></i></button>
<button class="delete__btn"><i class="far fa-trash-alt"></i></button>
</div>
`
item__sector.insertAdjacentHTML(position, item)
return item__sector
}
// load todo item from localstorage when page is loaded
document.addEventListener("DOMContentLoaded", getLocalStorage)
// add item to the item sector
add__btn.addEventListener("click", e => {
e.preventDefault()
const input__value = todo__input.value
if (input__value.trim() === "") { return }
createToDoItem(input__value)
saveLocalStorage(input__value)
todo__input.value = ""
})
// keypress Enter
document.addEventListener("keypress", e => {
if (e.keyCode == 13) {
e.preventDefault()
const input__value = todo__input.value
if (input__value.trim() === "") { return }
createToDoItem(input__value)
saveLocalStorage(input__value)
todo__input.value = ""
}
})
// the function on item (done, edit, and delete)
item__sector.addEventListener("click", e => {
const parent = e.target.parentElement
// done
if (e.target.classList.contains("done__btn")) {
e.target.nextElementSibling.classList.toggle("done__color")
}
// edit the todo item s
if (e.target.classList.contains("edit__btn")) {
if (e.target.previousElementSibling.disabled.disabled == true) {
e.target.previousElementSibling.disabled = !e.target.previousElementSibling.disabled
} else {
const todos = checkLocalStorage()
if (edit__index === -1) {
const valueBeforeEdit = e.target.previousElementSibling.getAttribute("value")
edit__index = todos.indexOf(valueBeforeEdit)
} else {
const valueAfterEdit = e.target.previousElementSibling.value
editLocalStorage(edit__index, valueAfterEdit)
edit__index = -1
}
e.target.previousElementSibling.disabled = !e.target.previousElementSibling.disabled
e.target.previousElementSibling.setAttribute("value", e.target.previousElementSibling.value)
}
}
// delete todo item
if (e.target.classList.contains("delete__btn")) {
parent.remove()
deleteLocalStorage(e.target.previousElementSibling.previousElementSibling)
}
})
// function for check todo status in the LocalStorage
function checkLocalStorage() {
let todos
if (localStorage.getItem("todos") === null) {
todos = []
} else {
todos = JSON.parse(localStorage.getItem("todos"))
}
return todos
}
// function for save localstorage
function saveLocalStorage(todo) {
const todos = checkLocalStorage()
todos.push(todo)
localStorage.setItem("todos", JSON.stringify(todos))
}
// function for get item and render to the screen from localstorage
function getLocalStorage() {
const todos = checkLocalStorage()
todos.forEach(todo => {
createToDoItem(todo)
})
}
// edit localStorage
function editLocalStorage(editIndex, editValue) {
const todos = checkLocalStorage()
todos.splice(editIndex, 1, editValue)
localStorage.setItem("todos", JSON.stringify(todos))
debugger
}
Note:
There is an edge case of having more than one todo item with the same value that you need to solve for.
Related
I have an app that stores items into locations in localStorage and then displays the items in HTML.
One of the reasons i wanted to use Svelte was for reactive variables, but whenever I attempt to use a reactive variable that changes whenever localStorage.current_items changes, the ItemList variable doesn't change.
The only way I could get it to work is by using setInterval but that is not a great way to do it. How can I make it so that ItemList changes properly when the localStorage.current_items string changes.
<script lang="ts">
import {
getData,
createItem,
createLocation,
closeItem,
} from './lib/database.js';
import LocationSelector from './lib/LocationSelector.svelte';
import { flip } from 'svelte/animate';
import { writable } from 'svelte/store';
let DB = getData();
// load items from localstorage.items
let ItemList = [];
let Location;
setInterval(() => {
Location = localStorage.current_items;
ItemList = JSON.parse(localStorage.current_items).items;
}, 500);
console.log(ItemList);
let newItem = '';
let filter_showClosed = false;
function addNewItem(e) {
e.preventDefault();
console.log(newItem);
const newItemInput = document.querySelector(
'#newItemInput'
) as HTMLInputElement;
createItem(JSON.parse(Location).id, newItem);
newItem = '';
}
function newItemKeyDown(e) {
if (e.keyCode === 13) {
addNewItem(e);
}
}
</script>
<LocationSelector />
<div class="app">
<input
type="text"
id="newItemInput"
bind:value={newItem}
placeholder="Add a new item"
on:keydown={newItemKeyDown}
/>
<button
id="filter_showClosed"
data-active="false"
on:click={function () {
filter_showClosed = !filter_showClosed;
let el = document.getElementById('filter_showClosed');
if (filter_showClosed) {
el.innerHTML = 'Hide closed';
el.dataset.active = 'true';
} else {
el.innerHTML = 'Show closed';
el.dataset.active = 'false';
}
}}>Show closed</button
>
<!-- <button
id="deleteClosed"
on:click={function () {
let it = items;
for (let i = 0; i < it.length; i++) {
if (it[i].closed == true) {
it.splice(i, 1);
}
}
items = it;
sort_items(items);
}}>Delete all closed</button
> -->
<div class="list">
{#each ItemList as item, index (item.id)}
<div class="item {item.closed}" animate:flip={{ duration: 100 }}>
{#if item.closed == false || (filter_showClosed == true && item.closed == true)}
<div>
<img
src="/up.svg"
class="item-icon"
class:closed={item.closed == true}
alt="move item up in priority"
on:click={function () {
// increaseLevel({ item });
}}
/>
{item.name} ({index})
</div>
<div>
{#if item.closed == false}
<img
src="/close.svg"
class="item-icon"
alt="close item"
on:click={function () {
console.log(Location.id);
closeItem(JSON.parse(Location).id, item.id);
}}
/>
{/if}
</div>
{/if}
</div>
{/each}
</div>
</div>
<style>
</style>
I tried using this writeable method, but that didn't work either as the variable still didn't change.
import { writable } from 'svelte/store';
const ItemList = writable([]);
let Location = {};
let newItem = '';
let filter_showClosed = false;
function addNewItem(e) {
e.preventDefault();
console.log(newItem);
const newItemInput = document.querySelector(
'#newItemInput'
) as HTMLInputElement;
createItem(Location.id, newItem);
newItem = '';
}
function newItemKeyDown(e) {
if (e.keyCode === 13) {
addNewItem(e);
}
}
// Update the Location object with the current value of localStorage.current_items as an object
Location = JSON.parse(localStorage.current_items);
// Update the ItemList store with the new location's items
ItemList.set(Location.items);
You should use a store that fully wraps the access to localStorage.
Something like:
function localStorageStore(key, initial) {
const value = localStorage.getItem(key)
const store = writable(value == null ? initial : JSON.parse(value));
store.subscribe(v => localStorage.setItem(key, JSON.stringify(v)));
return store;
}
Reading and writing is just a regular store, but on initial load the value comes from the storage and on setting the value, it is also written to storage.
When a user enters a title and amount, it gets pushed to an array. If the item is an expense, it gets pushed to an expense array of objects, if it's an income, it gets pushed to an income array of objects. Then either the displayIncome or displayExpense functions render a component so that it's displayed. The issue that i'm having is that every time I press the submit button, the app displays the previous item as one item and also the previous item with the new item as another individual item. If there are two items in the array, the app will display (item1) ((item1) + (item2)). The picture shows my issue. How do I get the app to only display one item for each item in the array?
let expense_list = []
let income_list = []
addExpense.addEventListener('click', () =>{
if(expenseTitle.value == '' || expenseAmount.value == ''){
return;
}
let expense = {
type: 'expense',
title: expenseTitle.value,
amount: expenseAmount.value,
id: Date.now()
}
expense_list.push(expense)
console.log(expense_list)
clearExpense()
displayExpense()
})
addIncome.addEventListener('click', () =>{
if(incomeTitle.value == '' || incomeAmount.value == ''){
return;
}
let income = {
type: 'income',
title: incomeTitle.value,
amount: incomeAmount.value,
id: Date.now()
}
income_list.push(income)
console.log(income_list)
clearIncome()
displayIncome()
})
const clearExpense = () =>{
expenseTitle.value = '';
expenseAmount.value = '';
}
const clearIncome = () =>{
incomeTitle.value = ''
incomeAmount.value = ''
}
const displayExpense = () =>{
expense_list.map((entry) =>{
return expenseList.innerHTML += `<li id = "${entry.id}" class= "${entry.type}">
<div class = "entry">${entry.title}: $${entry.amount}</div>
<div class="icon-container">
<div class = "edit" id="${entry.id}"></div>
<div class ="delete" id="${entry.id}"></div>
</div>
</li>`
})
}
const displayIncome = () =>{
income_list.map((entry) =>{
return incomeList.innerHTML += `<li id = "${entry.id}" class= "${entry.type}">
<div class = "entry">${entry.title}: $${entry.amount}</div>
<div class="icon-container">
<div class = "edit" id="${entry.id}"></div>
<div class ="delete" id="${entry.id}"></div>
</div>
</li>`
})
}
I've tried just using one array for expenses and incomes, and using forEach but every time I get the same result.
Clear the expenseList.innerHTML before mapping.
Something like that
const displayExpense = () =>{
expenseList.innerHTML = ''
expense_list.map((entry) =>{ ....
I am almost done with my to-do app, what is left is to do the local storage for the completed list and edited task.
The local storage I have done for when the task is added and removed. But I am not sure how to do the local storage for when the task is set to complete and when the task has been edited.
HTML
<div class="form">
<input class="user-input" type="text">
<input class="date" type="date">
<input class="time" type="time">
<button onclick="addTask()" class="add" id="add">+</button>
</div>
<div class="list"></div>
JS
//local storage key
const STORAGE_KEY = "tasks-storage-key";
// variables object
const el = {
form: document.querySelector(".form"),
input: document.querySelector(".user-input"),
list: document.querySelector(".list"),
date: document.querySelector(".date"),
time: document.querySelector(".time"),
};
const updateEl = {
formUpdate: document.querySelector(".form-update"),
inputUpdate: document.querySelector(".user-input"),
modal: document.querySelector(".modal"),
dateUpdate: document.querySelector(".date-update"),
timeUpdate: document.querySelector(".time-update"),
};
//Create ID
const createId = () =>
`${Math.floor(Math.random() * 10000)}${new Date().getTime()}`;
//variable of empty array that gets new task
let taskList = JSON.parse(window.localStorage.getItem(STORAGE_KEY) ?? "[]");
renderList();
function makeNewTask() {
const data = {
id: createId(),
taskNew: el.input.value,
taskDate: el.date.value,
taskTime: el.time.value,
};
return data;
}
function updateTask() {
const dataUpdate = {
id: createId(),
inputUpdate: updateEl.inputUpdate.value,
dateUpdate: updateEl.dateUpdate.value,
timeUpdate: updateEl.timeUpdate.value,
};
return dataUpdate;
}
function renderList() {
// This resets the list innerHTML to the new list
el.list.innerHTML = taskList.map(function (data) {
return `<div class="task">
<div class="task-content">
<div class="task" data-id="${data.id}">
<input class="new-task-created" value="${data.taskNew}" readonly></input>
<input class="due-date" type="date" value="${data.taskDate}" readonly></input>
<input class="due-time" type="time" value="${data.taskTime}" readonly></input>
</div>
<div class="action-buttons">
<button onclick="editItem(event)" class="edit" data-id="${data.id}">Edit</button>
<button onclick="deleteItem(event)" class="delete" data-id="${data.id}">Delete</button>
<button onclick="completeItem(event)" class="complete" data-id="${data.id}">Complete</button>
</div>`;
})
el.input.value = "";
}
//event listner that listens for add button.
function addTask() {
taskList.push(makeNewTask());
// store the list on localstorage because data changed
storeList();
// render list again because you've added a new entry
renderList();
}
//function that removes task from array with delete button.
function deleteItem(event) {
taskList.splice(taskList.indexOf(event.target.dataset.id), 1);
// store the list on localstorage because data changed
storeList();
// render list again because entry was removed
renderList();
}
//function that stores task list.
function storeList() {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(taskList));
}
//function that that edits tasks with date and time.
function editItem(event) {
const editEl = event.target.closest(".task");
let taskUpdate = editEl.querySelector(".new-task-created");
let dateUpdate = editEl.querySelector(".due-date");
let timeUpdate = editEl.querySelector(".due-time");
let editbtn = editEl.querySelector(".edit");
if (editbtn.innerHTML.toLowerCase() == "edit"){
taskUpdate.removeAttribute("readonly");
dateUpdate.removeAttribute("readonly");
timeUpdate.removeAttribute("readonly");
taskUpdate.focus();
editbtn.innerHTML = "Save";
}
else{
taskUpdate.setAttribute("readonly", "readonly");
dateUpdate.setAttribute("readonly", "readonly");
timeUpdate.setAttribute("readonly", "readonly");
editbtn.innerHTML = "Edit";
}
}
//function that that completes task.
function completeItem(event) {
const element = event.target.closest(".task-content");
let taskItem = element.querySelector(".new-task-created");
let dateItem = element.querySelector(".due-date");
let timeItem = element.querySelector(".due-time");
// style..
taskItem.style.textDecoration = "line-through";
dateItem.style.textDecoration = "line-through";
timeItem.style.textDecoration = "line-through";
}
I have added a screenshot of the section of the code I am focusing on, I just put the entire code so you can see the flow.
here in some changes in your js file look into it.
in editItem function on behalf of i we change value in taskList.
in completeItem function on behalf of i we add one more prop in object textDecoration: true and in renderList function we use prop to add style.
pass index i to each button action in function like editItem, deleteItem, completeItem .
//local storage key
const STORAGE_KEY = "tasks-storage-key";
// variables object
const el = {
form: document.querySelector(".form"),
input: document.querySelector(".user-input"),
list: document.querySelector(".list"),
date: document.querySelector(".date"),
time: document.querySelector(".time"),
};
const updateEl = {
formUpdate: document.querySelector(".form-update"),
inputUpdate: document.querySelector(".user-input"),
modal: document.querySelector(".modal"),
dateUpdate: document.querySelector(".date-update"),
timeUpdate: document.querySelector(".time-update"),
};
//Create ID
const createId = () =>
`${Math.floor(Math.random() * 10000)}${new Date().getTime()}`;
//variable of empty array that gets new task
let taskList = JSON.parse(window.localStorage.getItem(STORAGE_KEY) ?? "[]");
renderList();
function makeNewTask() {
const data = {
id: createId(),
taskNew: el.input.value,
taskDate: el.date.value,
taskTime: el.time.value,
};
return data;
}
function updateTask() {
const dataUpdate = {
id: createId(),
inputUpdate: updateEl.inputUpdate.value,
dateUpdate: updateEl.dateUpdate.value,
timeUpdate: updateEl.timeUpdate.value,
};
return dataUpdate;
}
function renderList() {
// This resets the list innerHTML to the new list
// <input class="new-task-created" value="${data.taskNew}" readonly style="text-decoration: 'line-through'"></input>
el.list.innerHTML = taskList.map(function (data, i) {
return `<div class="task">
<div class="task-content">
<div class="task" data-id="${data.id}" >
<input class="new-task-created" value="${data.taskNew}" readonly style="${data.textDecoration ? 'text-decoration: line-through': ''}"></input>
<input class="due-date" type="date" value="${data.taskDate}" readonly></input>
<input class="due-time" type="time" value="${data.taskTime}" readonly></input>
</div>
<div class="action-buttons">
<button onclick="editItem(event, ${i})" class="edit" data-id="${data.id}">Edit</button>
<button onclick="deleteItem(event, ${i})" class="delete" data-id="${data.id}">Delete</button>
<button onclick="completeItem(event, ${i})" class="complete" data-id="${data.id}">Complete</button>
</div>`;
})
el.input.value = "";
}
//event listner that listens for add button.
function addTask() {
taskList.push(makeNewTask());
// store the list on localstorage because data changed
storeList();
// render list again because you've added a new entry
renderList();
}
//function that removes task from array with delete button.
function deleteItem(event, i) {
taskList.splice(i, 1);
// store the list on localstorage because data changed
storeList();
// render list again because entry was removed
renderList();
}
//function that stores task list.
function storeList() {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(taskList));
}
//function that that edits tasks with date and time.
function editItem(event, i) {
const editEl = event.target.closest(".task");
let taskUpdate = editEl.querySelector(".new-task-created");
let dateUpdate = editEl.querySelector(".due-date");
let timeUpdate = editEl.querySelector(".due-time");
let editbtn = editEl.querySelector(".edit");
if (editbtn.innerHTML.toLowerCase() == "edit") {
taskUpdate.removeAttribute("readonly");
dateUpdate.removeAttribute("readonly");
timeUpdate.removeAttribute("readonly");
taskUpdate.focus();
editbtn.innerHTML = "Save";
}
else {
taskUpdate.setAttribute("readonly", "readonly");
dateUpdate.setAttribute("readonly", "readonly");
timeUpdate.setAttribute("readonly", "readonly");
editbtn.innerHTML = "Edit";
taskList[i] = {
id: taskList[i].id,
taskNew: taskUpdate.value,
taskDate: dateUpdate.value,
taskTime: timeUpdate.value
}
// store the list on localstorage because data changed
storeList();
// render list again because you've added a new entry
renderList();
}
}
//function that that completes task.
function completeItem(event, i) {
const element = event.target.closest(".task-content");
let taskItem = element.querySelector(".new-task-created");
let dateItem = element.querySelector(".due-date");
let timeItem = element.querySelector(".due-time");
// style..
taskItem.style.textDecoration = "line-through";
dateItem.style.textDecoration = "line-through";
timeItem.style.textDecoration = "line-through";
taskList[i] = {
...taskList[i],
textDecoration: true
}
console.log('taskList', taskList)
// store the list on localstorage because data changed
storeList();
// render list again because you've added a new entry
renderList();
}
For edited tasks I would first modify the updateTask() function so that it uses the same id as the originally created task:
//...
const taskData = {
id: createId(),
completed: false, // added
contents: el.input.value,
date: el.date.value,
time: el.time.value,
};
//...
You can modify the contents and the date/time to keep track of the last time it was modified. From there, you would do the simply call storeList() and renderList() to save to local storage and update the view.
For completed tasks I would either add a boolean property in the task data (something like completed) or a completion date (initially set to zero or null). From there you simply update and check for that value. And as for saving to local storage you would do the same: call storeList() and renderList().
I'm trying to add links to my navbar for searches that users have made, as well as if the user favorites the link. What I'm currently trying to achieve is that if, if the "past searched" section already contains the current search, don't add the current search to avoid duplicates. I am using localStorage to store this data with a stringified array (alreadySearched) and check if this array includes the current search; my problem is that the function always returns false. The same thing happens for the favorites dropdown. What am I doing wrong?
Here's my code:
// primary movie information (API #1)
var getMovie = function(title) {
$("#result").addClass("hidden")
$("#main").removeClass("hidden");
$("#search-form").trigger("reset");
//format the OMDB api url
var apiUrl = `http://www.omdbapi.com/?t=${title}&plot=full&apikey=836f8b0`
//make a request to the url
fetch(apiUrl)
.then(function(response) {
// request was successful
if (response.ok) {
response.json().then(function(movieData) {
// console.log(movieData)
var movieTitle = movieData.Title
getMovieId(movieTitle);
getSoundTrack(movieTitle);
getTrailer(movieTitle);
var movieObj = {
title: movieTitle,
}
var pastSearches = loadPastSearches();
var alreadySearched = false
if (pastSearches) {
pastSearches.forEach(s => {
if (s.title === movieTitle) {
alreadySearched = true;
}
})
}
if (!alreadySearched) {
for (var item of pastSearches) {
let searchEl = document.createElement("a")
let pastSearchTitle = item.title
$(searchEl).text(pastSearchTitle)
$(searchEl).addClass("past-search-item");
$("#past-search-dropdown").append(searchEl)
$(searchEl).click(function(e) {
e.preventDefault();
let title = pastSearchTitle
getMovie(title)
getQuotes(title)
});
}
}
saveSearch(movieObj)
showMovie(movieData);
});
} else {
alert("Error: title not found!");
}
})
.catch(function(error) {
alert("Unable to connect to CineXScore app");
console.log(error)
});
};
// save past search
var saveSearch = function(movieObj) {
var pastSearches = loadPastSearches();
pastSearches.push(movieObj);
localStorage.setItem("movieObjects", JSON.stringify(pastSearches))
}
loadPastSearches = function() {
var pastSearches = JSON.parse(localStorage.getItem("movieObjects"));
if (!pastSearches || !Array.isArray(pastSearches)) {
var pastSearches = []
}
return pastSearches;
}
// dropdown favorite soundtrack buttons
var saveTrack = function(trackObj) {
var faveTracks = JSON.parse(localStorage.getItem("trackObjects"));
if (!faveTracks || !Array.isArray(faveTracks)) {
var faveTracks = []
}
var alreadySearched = false
if (faveTracks) {
faveTracks.forEach(t => {
if (t.name === trackObj.name) {
alreadySearched = true;
}
})
}
if (!alreadySearched) {
let trackEl = document.createElement("a")
$(trackEl).addClass("fave-track");
$(trackEl).text(trackObj.name);
$(trackEl).attr("href", trackObj.url);
$(trackEl).attr("target", "_blank")
$("#favorite-tracks-dropdown").append(trackEl)
}
faveTracks.push(trackObj);
localStorage.setItem("trackObjects", JSON.stringify(faveTracks))
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Navigation Menu -->
<nav class="navbar navbar-default navbar-fixed-top">
<a id="logo" class="navbar-brand">CineXScore</a>
<div class="dropdown navbar-brand">Past Searches
<i class="fa fa-caret-down"></i>
<div id="past-search-dropdown" class="dropdown-content">
<a id="clear-searches">Clear</a>
</div>
</div>
<div class="dropdown navbar-brand">Favorite Tracks
<i class="fa fa-caret-down"></i>
<div id="favorite-tracks-dropdown" class="dropdown-content">
<a id="clear-favorites">Clear</a>
</div>
</div>
</nav>
This is a simple implementation that I think might help you.
async function fetchMovie(movieTitle) {
const apiUrl = `http://www.omdbapi.com/?t=${movieTitle}&plot=full&apikey=836f8b0`;
let res = await fetch(apiUrl);
res = await res.json();
const title = res.Title;
saveSearch(title); // Should only pass the string:title
}
fetchMovie('spiderman');
function saveSearch(title) {
if (!localStorage.getItem('movies')) localStorage.setItem('movies', ''); // Initialize the localStorage
// e.g: (In localStorage)
// Avenger,Spiderman,The Antman etc..
// return this string & convert into an array
let movies = localStorage
.getItem('movies')
.split(',')
.filter((n) => n);
// Check if the title is already exists
if (!movies.includes(title)) {
movies.push(title);
}
// Also store in localStorage as a string seperated by commas (,)
movies = movies.join(',');
localStorage.setItem('movies', movies);
}
** I want when to click on the active button if the checkbox is checked to add filtered class in HTML element but it doesn't work and give me an undefined error in this line check.parentElement.classList.add("filtered"); **
<ul class="ul-list"></ul>
</section>
</main>
<footer class="footer">
<button class="all footer-btn">All</button>
<button class="active footer-btn">Active</button>
<button class="complete footer-btn">Complete</button>
</footer>
let check = document.querySelectorAll(".complete-txt");
let complete_btn = document.querySelector(".complete");
let active_btn = document.querySelector(".active");
let all_btn = document.querySelector(".all");
let edit_list = document.querySelector(".edit-list");
let main_text = document.querySelector(".main-text");
let list_item = document.querySelector(".list-item");
let footer = document.querySelector(".footer");
const generateTemplate = (todo) => {
const html = `
<li class="list-item">
<input type="checkbox" class="complete-txt" name="" id="check"><span class="main-text">${todo}</span><div class="edit-list"></div><div class="delete-list"></div>
</li>
`;
list.innerHTML += html;
};
// add todos event
addForm.addEventListener("submit", (e) => {
e.preventDefault();
const todo = addForm.add.value.trim();
if (todo.length) {
generateTemplate(todo);
addForm.reset();
}
});
active_btn.addEventListener("click", function () {
let check_id = document.querySelector(".complete-txt");
// check.forEach(function () {
debugger;
if (check.checked !== "true") {
check.parentElement.classList.add("filtered");
console.log("hi");
}
// });
// console.log("hi");
console.log("hi");
// console.log(check.checked.value);
});
if the larger document fixes all other inconcistencies you should be able to change the eventlistener to
active_btn.addEventListener("click", function () {
let check_id = document.querySelector(".complete-txt");
if (check_id.checked !== "true") {
check_id.parentElement.classList.add("filtered");
}
});
BUT!!! this will not "fix" all of your errors, like defining let check before the checkbox is created with generateTemplate