Day15 of #100DaysOfCode
Hii folks 🙌
Today I have completed the 15th video of JavaScript30!
Project 15: LocalStorage and Event Delegation
Source: https://javascript30.com
Learnings:
The JS was given to us
const addItems = document.querySelector(".add-items");
const itemsList = document.querySelector(".plates");
const items = [];
We have handles to the form where the user inputs new items and the list where the items are displayed. The items
array holds all the items.
The main steps involved completing our app
- Add new items to the
items
array - Display the items in the
items
array - Toggle an item
- Save the list to local storage
Adding new items
We add new items using an HTML form. Submitting a form by default makes a get request and goes to the new URL. We call e.preventDefault()
to prevent the default behavior.
function addItem(e) {
e.preventDefault();
const text = (this.querySelector('[name=item]')).value;
const item = {
text,
done: false
}; items.push(item); // display the list - populateList();
// store to local storage - localStorage.set() this.reset();
}addItems.addEventListener('submit', addItem);
In addItem()
, this
refers to the form.add-items
DOM object. We then select the text input element and get the text inside of it. We create a new items object and then push it into the items list. Once it is added we call reset()
on the form to clear the input text box.
Display the items
populateList()
does the work of taking in an array and displaying the list. We could have populateList()
just use the global items
and itemsList
variables, but that would be hardcoding, it's better to pass the variables in case we ever want to use the functions for anything else.
function populateList(plates = [], platesList) {
platesList.innerHTML = plates.map((plate, i) => {
return `
<li>
<input type="checkbox" data-index=${i} id="item${i}" ${plate.done ? 'checked' : ''} />
<label for="item${i}">${plate.text}</label>
</li>
`;
}).join('');
}function addItem(e){
//...
// display the list - populateList()
populateList(items, itemsList)
}
populateList()
uses template strings and [].map
to create <li>
elements from each element in the array, which is late concatenated into one string which platesList.innerHTML
is set to. addItem
uses populateList
to render all the current items.
Toggle an item
toggleDone
deals with the click event to toggle an item. We can attach a listener on the checkbox element, but the moment we add a new item, all <li>
elements are recreated by populateList
. Hence adding an event listener on those items makes no sense. We solve this issue by using event delegation - we let the parent element take care of the click event to toggle an item. The parent in this case is the ul.item-plates
element.
function toggleDone(e) {
if (!e.target.matches('input')) return; // skip this unless it's an input
const el = e.target;
const index = el.dataset.index;
items[index].done = !items[index].done;
populateList(items, itemsList);
}itemsList.addEventListener('click', toggleDone);
If you had paid close attention to the populateList
function you'd see that the input element for the item has data-index=${i}
where i
is the index of that item in the items
array. So now toggleDone
checks if the event target is an input element (only input element being a checkbox), extracts the index from the data attribute, toggles the done
in the items
array, and then re-renders the list by calling populateList
.
Save the list to LocalStorage
We want to persist the list after a refresh or for a later point in time, for this we’ll use local storage. Local storage is a key-value store where the key and value are strings.
A simple example
// set the value "Tom" for key "myCat" in the local storage
localStorage.setItem('myCat', 'Tom'); // cat has value "Tom"
var cat = localStorage.getItem('myCat'); //remove the "myCat" key from local storage
localStorage.removeItem('myCat');
You can learn more about Local Storage @ MDN Docs.
Since we want to keep the local storage in sync with the UI, we’ll update the local storage whenever we call populateList()
.
function toggleDone(e) {
//...
localStorage.setItem('items', JSON.stringify(items));
populateList(items, itemsList);
}function addItem(e) {
//...
localStorage.setItem('items', JSON.stringify(items));
populateList(items, itemsList);
//...
}
Also, we need to get the items from local storage when we load the page. We’ll modify items
array to take read from the local storage first, if it doesn't have an 'items' key, we'll assign it to an empty array as we had earlier.
const items = JSON.parse(localStorage.getItem('items')) || [];
Today I learned (T-I-L):
- About Local Storage of Browser
- Event Delegation
That is all for Day15 ✅
Thanks for reading, See you tomorrow!