NOVINKA: Staň se datovým analytikem od 0 Kč a získej jistotu práce, lepší plat a nové kariérní možnosti. Více informací:

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:

Tvoje stránka
localhost

Ú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é:

Tvoje stránka
localhost

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

 

Předchozí článek
Formát JSON
Všechny články v sekci
Objektově orientované programování v JavaScriptu
Přeskočit článek
(nedoporučujeme)
OOP diář v JavaScriptu - Formátování a mazání záznamů
Článek pro vás napsal Šimon Raichl
Avatar
Uživatelské hodnocení:
258 hlasů
Autor se věnuje především vývoji v JavaScriptu
Aktivity