Lekce 8 - OOP diář v JavaScriptu - Ukládání, řazení, seskupování
V minulé lekci, Formát JSON, jsme si představili populární formát JSON.
V dnešním tutoriálu objektově orientovaného programování v
JavaScriptu se budeme opět věnovat našemu diáři. Doplníme si ho
tak, aby pracoval s úložištěm localStorage
. Dále ještě
upravíme výpis našich záznamů a budeme je
seskupovat podle data.
Implementace
localStorage
v diáři
V předchozích lekcích jsme se naučili vše potřebné k tomu, abychom
mohli upravit náš diář tak, aby se jeho data při obnovení stránky
neztratila. Ukládat budeme pouze pole #zaznamy
naší třídy
Diar
. Pole nejprve převedeme na JSON řetězec a poté tento
řetězec jednoduše uložíme pod klíčem zaznamy
do úložiště
localStorage
.
Načítání
V konstruktoru třídy Diar
v souboru Diar.js
zavedeme dva nové řádky kódu, které načtou záznamy uložené v
localStorage
:
constructor(jazyk = "cs-CZ") { const zaznamyZeStorage = localStorage.getItem("zaznamy"); this.#zaznamy = zaznamyZeStorage ? JSON.parse(zaznamyZeStorage) : []; this.#jazyk = jazyk; this.#nastavUdalosti(); }
Do proměnné zaznamyZeStorage
vybíráme naše záznamy z
localStorage
, kde jsou uložené pod klíčem zaznamy
.
Dále kontrolujeme, zda se nám vůbec podařilo nějaké záznamy z
úložiště získat. Pokud ne, proměnná zaznamyZeStorage
nabude
hodnoty null
. Proto zde máme ternární
operátor, který známe ze základního kurzu JavaScriptu z lekce Podmínky
v JavaScriptu potřetí. Pokud proměnná zaznamyZeStorage
neobsahuje hodnotu null
, pak obsahuje náš JSON řetězec, který
následně parsujeme pomocí metody JSON.parse()
na JavaScriptové
pole a přiřazujeme jej vlastnosti #zaznamy
. V opačném
případě vlastnosti #zaznamy
přiřazujeme prázdné pole.
Ukládání
Načítání záznamů z localStorage
máme, nyní přidáme i
jejich ukládání při přidání nového záznamu. Záznamy
budeme ukládat jak do pole #zaznamy
, tak do
localStorage
. Pracovat v celé aplikaci jen s
localStorage
by vyžadovalo neustálé převádění záznamů z
objektu na text a zpět. Proto jej využíváme jen pro načítání na
začátku a pro průběžné ukládání.
Ukládání přidáme konkrétně do obslužné funkce potvrzovacího
tlačítka, kterou vytváříme v naší pomocné metodě
#nastavUdalosti()
třídy Diar
:
#nastavUdalosti() { this.#potvrditButton.onclick = () => { const zaznam = new Zaznam(this.#nazevInput.value, this.#datumInput.value); this.#zaznamy.push(zaznam); const jsonZaznamy = JSON.stringify(this.#zaznamy); localStorage.setItem("zaznamy", jsonZaznamy); this.vypisZaznamy(); }; }
Vidíme, že ihned po přidání nového záznamu do pole
#zaznamy
dané pole převádíme na JSON řetězec pomocí metody
JSON.stringify()
. Řetězec následně ukládáme pod klíčem
zaznamy
do localStorage
.
Můžeme projekt zkusit spustit, přidat úkoly a znovu načíst stránku:
Úkoly v aplikaci již nyní zůstávají a to znamená, že máme první reálně použitelnou objektovou aplikaci. Gratulujeme!
Výpis záznamů
Celkem snadno jsme vyřešili problém s ukládáním. Pojďme ještě upravit výpis záznamů tak, aby byly seřazeny podle data a záznamy ze stejného dne byly seskupeny a zobrazeny společně v jednom bloku.
Řazení
Nejdříve si ve třídě Diar
naimplementujeme pomocnou metodu
#seradZaznamy()
, která seřadí záznamy v našem poli
#zaznamy
podle jejich data vzestupně. Metodu přidáme do třídy
Diar
stejně jako předchozí metody, třeba hned pod metodu
#nastavUdalosti()
:
#seradZaznamy() { this.#zaznamy.sort(function (zaznam1, zaznam2) { return (new Date(zaznam1.datum) - new Date(zaznam2.datum)); }); }
K řazení používáme metodu sort()
, která je dostupná na
každém poli. Ta dokáže pole seřadit postupným porovnáváním dvojic
prvků. Jako parametr přijímá porovnávací funkci, která definuje jakým
způsobem se mají dva prvky v poli porovnat.
V našem případě funkce vždy porovnává datum ze dvou záznamů. Hodnota
data je ale ve vlastnosti datum
uložená jako textový řetězce.
Proto ji nejprve převádíme na instance třídy Date
, abychom ji
mohli snadněji porovnat. Porovnání dvou hodnot typu Date
provádíme jednoduše pomocí operátoru -
, čímž se vrátí
jejich rozdíl v milisekundách. Pokud bude první datum až po tom druhém,
vrátí se záporné číslo. Pokud bude datum obou záznamů stejné, vrátí
se 0
. Jinak se vrátí kladné číslo. Právě kladné, záporné
nebo nulové číslo metoda sort()
pro svou práci potřebuje a
tím zjistí, zda je datum větší, menší nebo rovné.
Metodu #seradZaznamy()
jsme definovali jako
privátní. Nebudeme ji totiž volat nikde mimo třídu Diar
.
Metodu #seradZaznamy()
budeme volat před každým výpisem
záznamů v metodě vypisZaznamy()
:
vypisZaznamy() { this.#seradZaznamy(); this.#vypisElement.innerHTML = ""; for (const zaznam of this.#zaznamy) { this.#vypisElement.innerHTML += `<h3>${zaznam.nazev}</h3>kdy: ${zaznam.datum}<br>splněno: ${zaznam.splneno}`; } }
Seřazení bychom mohli volat pouze po přidání nového záznamu a po jejich načtení, aby se nemuselo volat při každém výpisu. Nevýhodou tohoto řešení by ovšem bylo, že bychom na něj mohli zapomenout při jiné manipulaci se záznamy.
Po spuštění diáře se z localStorage
načtou všechny
dříve uložené úkoly. Pokud tam nějaké jsou, zobrazí se rovnou seřazené
podle data.
Optimalizace výpisu
Naše stávající řešení výpisu záznamů na stránku není úplně
ideální. Změna vlastnosti innerHTML
totiž vymaže a
znovu vytvoří veškerý obsah HTML elementu, což může být
při větším množství dat poměrně náročné, zejména u velkých
elementů. V našem případě pravděpodobně žádné problémy s výkonem
nepocítíme, i tak si ale ukážeme lepší řešení.
Záznamy, konkrétně jejich hodnoty (název, datum), budeme nyní přidávat
na stránku pomocí metody insertAdjacentHTML()
:
vypisZaznamy() { this.#seradZaznamy(); this.#vypisElement.innerHTML = ""; for (const zaznam of this.#zaznamy) { this.#vypisElement.insertAdjacentHTML("beforeend", `<h3>${zaznam.nazev}</h3>kdy: ${zaznam.datum}<br>splněno: ${zaznam.splneno}`); } }
Prvním parametrem této metody je umístění, kam se HTML v elementu vloží, druhým parametrem je samotný HTML kód. První parametr může nabývat čtyř různých hodnot, a to:
beforebegin
– před element,afterbegin
– po začátku elementu,beforeend
– před koncem elementu,afterend
– po elementu.
Lépe si to ještě můžeme vysvětlit podle následujícího schématu, kdy
<div>
s třídou seznam-ukolu
je náš
<div>
v aplikaci:
<!-- beforebegin --> <div class="seznam-ukolu"> <!-- afterbegin --> nějaký obsah (zde po vložení prvního záznamu bude onen první záznam) <!-- beforeend (sem vkládáme nové záznamy) --> </div> <!-- afterend -->
Výhodou použití metody insertAdjacentHTML()
je,
že nevede ke smazání a opětovnému vytvoření celého obsahu elementu při
každé změně.
Seskupování
Nakonec výpis záznamů ještě o kousek vylepšíme jejich seskupováním.
Budeme vypisovat datum a k tomuto datu vždy všechny záznamy v daný den.
Náš cyklus v metodě vypisZaznamy()
proto lehce upravíme:
vypisZaznamy() { this.#seradZaznamy(); this.#vypisElement.innerHTML = ""; let posledniDatum = null; for (const zaznam of this.#zaznamy) { if (zaznam.datum !== posledniDatum) { this.#vypisElement.insertAdjacentHTML("beforeend", `<h2>${zaznam.datum}</h2>`); } posledniDatum = zaznam.datum; this.#vypisElement.insertAdjacentHTML("beforeend", `<h3>${zaznam.nazev}</h3>splněno: ${zaznam.splneno}<hr>`); } }
Do proměnné posledniDatum
přiřazujeme hodnotu vlastnosti
datum
z předchozího záznamu. Na začátku je nastavena na
null
, protože ještě žádný záznam zpracovaný není. Kdykoliv
se v cyklu objeví jiné datum než to uložené, vypíše se nový nadpis s
datem. Tak se záznamy pro stejný den zobrazí seskupené.
Nyní máme vypsané úkoly se stejným datem pod sebou a seřazené:
V příští lekci, OOP diář v JavaScriptu - Formátování a mazání záznamů, do našeho objektového diáře v JavaScriptu přidáme několik dalších funkcí.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 0x (2.89 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript