Build a notes page that keeps its data, and survives damaged data.
What to build
Functions that load, save and draw a list of notes.
Requirements
readNotes()returns the saved array of notes from the keynotes. If nothing is saved, or if the saved text is damaged or is not an array, it returns an empty array.render()draws the current saved notes in#notes, with oneliper note, replacing what was there. Call it when the page loads.- Submitting the form trims the text, ignores a blank note, saves the longer list as JSON, empties the box and draws again.
- The
#clearbutton removes the keynotesand draws again.
Constraints
Use the store object from the first script, which has the same methods as localStorage, because storage is blocked in this practice frame. Do not change that script. The functions must have exactly these names.
Example
store.setItem("notes", JSON.stringify(["Buy rice"]));
Why it works
Treating storage as the single source of truth means that the page always shows what would be there after a reload. Stored text can be edited or damaged, so a page that trusts it can break every time it opens, which makes the try and the shape check essential.
Hints
Hint 1
readNotes uses try ... catch around JSON.parse, and checks the result with Array.isArray.
Hint 2
store.getItem gives null when nothing is saved. JSON.parse(null) gives null, so Array.isArray handles that too.
Hint 3
After any change, save the list and call render.
Solution
Show one correct solution (try it yourself first)
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Notes</title>
</head>
<body>
<form id="add">
<label for="note">New note</label>
<input id="note" autocomplete="off">
<button>Save</button>
</form>
<button id="clear">Clear all</button>
<ul id="notes"></ul>
<script>
// Stands in for localStorage, which is blocked in this practice frame.
const store = {
data: new Map([["notes", '["Buy rice"]']]),
getItem(key) { return this.data.has(key) ? this.data.get(key) : null; },
setItem(key, value) { this.data.set(key, String(value)); },
removeItem(key) { this.data.delete(key); },
};
</script>
<script>
const list = document.querySelector("#notes");
const input = document.querySelector("#note");
function readNotes() {
try {
const notes = JSON.parse(store.getItem("notes"));
return Array.isArray(notes) ? notes : [];
} catch (err) {
return [];
}
}
function render() {
list.replaceChildren();
for (const note of readNotes()) {
const li = document.createElement("li");
li.textContent = note;
list.append(li);
}
}
document.querySelector("#add").addEventListener("submit", (event) => {
event.preventDefault();
const text = input.value.trim();
if (text === "") return;
store.setItem("notes", JSON.stringify([...readNotes(), text]));
input.value = "";
render();
});
document.querySelector("#clear").addEventListener("click", () => {
store.removeItem("notes");
render();
});
render();
</script>
</body>
</html>