3

Aktualizace stránky

Pokud se data na naší stránce změní, je potřeba na to správným způsobem zareagovat a stránku aktualizovat.

Pokud ve své aplikaci používáme data z nějakého veřejného API, většinou je stahujeme pouze ke čtení. Málokterý veřejný server by nám jen tak dovolil na něm data upravovat. Pokud však píšeme aplikaci, ve které pužíváme vlastní data, většinou si vytvoříme vlastní databázi a vlastní API, do kterého pak můžeme i zapisovat. V této lekci si ukážeme, jak můžeme pomocí dotazů na API data měnit.

Typy dotazů na server

V minulé lekci jsme posílali dotazy na API tímto způsobem.

fetch('https://api.abalin.net/today?country=cz')

Tímto způsobem se posílá základní typ dotazu, kterému říkáme GET. Tento dotaz má za úkol získat nějaká data ze serveru. Typů dotazů však existuje více.

POST
Poslat data na server
PUT
Přidat prvek do nějaké kolekce
DELETE
Odstranit prvek z nějaké kolekce

Pokud chceme pomocí funkce fetch poslat jiný dotaz než GET, musíme specifikovat několik věcí:

  • typ dotazu, například POST,
  • takzvaný Content-Type, tedy v jakém formátu data na server posíláme. Nejčastěji to bude JSON.
  • tělo dotazu, tedy samotná data ve formátu JSON.

Tělo dotazu se na server posíká jako řetězec obsahující JSON. Pokud tedy chceme na server odeslat JavaScriptový objektu, musíme si jej převést na řetězec. K tomu použijeme funkci JSON.stringify. Vyzkoušíme si ji v konzoli.

> JSON.stringify({name: 'Petr', age: 25})
"{"name":"Petr","age":25}"

Takto si můžeme z jakéhokoliv objektu připravit řetězec, který pak můžeme poslat na server.

Představme si zatím fiktivní stránku https://it-seznamka.cz, která by mohla mít API endpoint register, kde bychom pomocí POST mohlit zaregistrovali nového uživatele. Výslední kód by vypadal takto.

fetch('https://it-seznamka.cz/register', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Petr', 
    age: 25
  }),
})

Nákupní seznam

Abychom si komunikaci se serverm vykoušeli na nějakém skutečném API, navážeme na naši aplikaci o nákupních seznamech. API této aplikace najdete na adrese http://apps.kodim.cz/daweb/shoplist.

Cvičení: Manipulace s daty na serveru

1

Přidání seznamu

to dáš
  1. Založte si prázdnou stránku s JavaScriptovým programem.
  2. Prohlédněte si dokumentaci a podívejte se, jak se dělá přidání nového nákupního seznamu.
  3. Vytvořte na stránce textové políčko a tlačítko s nápiem ‘Nový seznam’. Jakmile uživatel do políčka zadá název nového seznamu, pomocí volání funkce fetch vytvořte na serveru nový seznam s tímto názvem. Zadávejte názvy seznamů pouze malými písmeny bez mezer a bez diakritiky!
  4. Podívejte se, jak vypadá adresa pro získání všech seznamů, zadejte ji do adresní řádky prohlížeče a vyzkoušejte, že se váš nový seznam skutečně přidal.
2

Přidání položky do seznamu

to dáš

Pokračujte se stránkou z předchozího cvičení.

  1. Přidejte na stránku tlačítko s názvem ‘Nová položka’ a dvě textová políčka. Ta budou nyní sloužit k přidání nové položky do seznamu. Do jednoho políčka uživatel zadá název produktu a do druhého množství.
  2. Při stisknutí tlačítka zatím vytvořte jednoduchý objekt s vlastnostmi product a amount získanými od uživatele. Objekt si uložte do proměnné s názvem newItem.
  3. Pomocí funkce JSON.stringify vypište do konzole JSON verzi vaší nové položky. Toto je pro vaši kontrolu, abyste viděli, co přesně se později odešle na server.
  4. Prohlédněte si dokumentaci a podívejte se, jak se přidává položka do seznamu.
  5. Nechte uživatele zadat do políček na stránce název seznamu, produkt a množství. Po kliknutí na tlačítko ‘Nová položka’ přidejte do zadaného seznamu novou položku voláním funkce fetch. Nebuďte zatím zlí a přidávejte položky pouze do seznamů, které jste sami vytvořili.
  6. Podívejte se, jak vypadá adresa pro získání položek v seznamu. Zadejte ji do adresní řádky prohlížeče a vyzkoušejte, že se váš seznam skutečně aktualizoval.

Aktualizace obsahu stránky

V této části si ukážeme, jak můžeme aktualizovat obsah stránky, pokud se naše zobrazovaná data nějak změní. V naší aplikaci s nákupním seznamem můžeme například chtít přidat do seznamu novou položku. Abychom si malinko ulehčili situaci, zatím si nákupní seznam uložím natvrdo do proměnné.

const list = [
  {
    product: 'Rohlíky',
    amount: '10',
    bought: false,
  },
  {
    product: 'Rajčate',
    amount: '1kg',
    bought: false,
  },
];

Kód HTML naší stránky může vypadat například takto.

<body>
  <section id="list-section"></section>
  <script src="index.js"></script>
</body>

Z minulé lekce máme k dispozici komponentu ShoppingList, která umí vyrobit seznam položek. Můžeme tedy tento seznam vložit do sekce #list-section.

const ShoppingList = ({ items }) => {
  let resultHTML = '<ol class="shopping-list">';
  for (let i = 0; i < items.length; i += 1) {
    resultHTML += ShoppingItem(items[i]);
  }

  return resultHTML + '</ol>';
};

const listSection = document.querySelector('#list-section');
listSection.innerHTML = ShoppingList({ items: list });

Stránka je zatím poměrně statická. Zobrazuje pořád tentýž seznam. Určitě bychom chtěli uživateli umožnit přidat do seznamu nějakou položku. Naše pole je globální, můžeme to tedy zatím zkusit udělat programátorsky přímo z konzole.

> list.push({ product: 'koriandr', amount: '1 balení', bougth: false });
7

Naše pole se tímto rozroste o jeden prvek. K našemu zklamání však obsah stránky zůstává pořád stejný. Je to logické, protože obsah seznamu ol jsme v JavaScriptu vytvořili hned po načtení stránky. Změna našeho pole tento kód znovu magicky nespustí. Musíme jej spustit sami ve chvíli, kdy chceme říct, že se má obsah seznamu ol vytvořit znova podle nového obsahu pole list. Máme zde velkou výhodou v tom, že náš kód vytvářející obsah stránky dle pole list máme hezky zabalený v komponentě ShoppingList. Chceme-li tedy obsah stránky aktualizovat podle nových hodnot v poli list, stačí naši komponentu znova zavolat a vytvořit nové HTML.

listSection.innerHTML = ShoppingList({ items: list });

Všimněte si, že takto zcela přepíšeme původní obsah innerHTML celé sekce. Tím celou HTML strukturu vytváříme v podstatě úplně znova. Funkci ShoppingList tak můžeme zavolat pokaždé, když chceme, aby naše stránka zobrazila aktuální obsah našeho pole list. To nám dává svobodu si s polem dělat co chceme, přidávat položky, měnit položky, mazat položky a tak dále. Vždy jen pak musíme zavolat funkci ShoppingList, aby se změny projevily i v našem HTML. Můžete si to vyzkoušet rovnou z konzole a sledovat, jak stránka reaguje.

> list.push({ product: 'zázvor', amount: '30g', bought: false });
8
> listElm.innerHTML = ShoppingList({ items: list });
> list.shift();
> listElm.innerHTML = ShoppingList({ items: list });
> list[0] = { product: 'klíčky', amount: '20g', bought: true };
> listElm.innerHTML = ShoppingList({ items: list });

Zpracování vstupu od uživatele

Do teď jsme měnili obsah našeho pole programaticky. Nyní však chceme umožnit uživateli, aby mohl do nákupního seznamu sám přidat nějakou položku. K tomu budeme v HTML potřebovat textové políčka pro název a množství, a tlačítko pro provedení samotné akce.

<section id="list-section"></section>

<input type="text" id="product-input" />
<input type="text" id="amount-input" />
<button id="add-btn">Přidat</button>

<script src="index.js"></script>
</body>

Když uživatel klikne na tlačíko, musíme udělat tyto tři věci:

  1. získat příslušné hodnoty z textových políček,
  2. přidat do pole list nový objekt vytvořený z těchto hodnot,
  3. aktualizovat obsah seznamu ol voláním komponenty ShoppingList.
const addBtn = document.querySelector('#add-btn');
addBtn.addEventListener('click', () => {
  const name = document.querySelector('#name-product').value;
  const amount = document.querySelector('#amount-input').value;
  list.push({ product: product, amount: amount });
  
  const listSection = document.querySelector('#list-section');
  listSection.innerHTML = ShoppingList({ items: list });
});

Cvičení: Aktualizace stránky

3

Lokální čas

to dáš

Stáhněte si základ aplikace zobrazující lokální čas na vašem počítači. Prohlédněte si zdrojový kód. Máte dopředu k dispozici funkci localTime, která vrátí aktuální čas v tomto formátu.

{
  hours: 9,
  minutes: 16,
  sesonds: 25,
}

Komponenta Time zobrazuje tento čas na obrazovce. Můžete si vyzkoušet, že při obnovení stránky se skutečně zobrazí aktuální čas.

Na stránce s nachází připravené tlačítko. Pověste na něj funkci, která aktualizuje čas zobrazený na stránce. Provede to tak, že znova získá aktuální čas pomocí funkce localTime a zavolá komponentu Time.

4

Dopravní přestupky

to dáš

Představte si, že je vaším úkolem sledovat křižovatku, na které řidiči často porušují dopravní značení, a zaznamenat čas každého porušení. Stáhněte si základ aplikace. Prohlédněte si kód aplikace. Najdete zde pole offences, které obsahuje časy přestupků. Komponenta Offence, která zobrauje čas přestupku.

  1. Vytvořte komponentu OffenceList, která vyrobí HTML obsah pro element #offence-list podle pole offences.
  2. Na tlačítko #add-btn pověste funkci, která přidá do senzmau čas nového přestupku.
    1. Funkce nejdříve získá objekt obsahující aktuální čas voláním funkce localTime,
    2. pomocí metody push vloží do tento objekt do pole offences,
    3. aktualizuje obsah elementu #offence-list voláním funkce OffenceList.

Doporučené úložky na doma

5

Lokální čas

zapni hlavu

Stáhněte si základ aplikace zobrazující datum a čas v růnzých časových zónách.

  1. Vytvořte komponentu Time, která očekává props v tomto formátu:
    {
      zone: 'Europe/London',
      datetime: '2020-10-22T07:17:07.139635+01:00'
    }
    
  2. Při stisknutí tlačítka #btn-show použijte komponentu Time a zobrazte uvnitř elementu main data uvedená v předchozím kroku. Rozbalovací nabídku na stránce zatím ještě ignorujte.
  3. Upravte událost tlačítka tak, aby se na stránce zobrazil název časové zóny, kterou uživatel vybere z rozbalovací nabídky. Zobrazený čas zatím nechte stejný, vyřešíme jej v dalším kroku.
  4. K získání skutečného času použijeme veřejné API na adrese https://worldtimeapi.org. Čas pro časovou zónu Europe/London získáte na adrese
    https://worldtimeapi.org/api/timezone/Europe/London
    
    Nejdříve si tuto adresu otevřete v prohlížeči a seznamte se s formátem dat, který tento endpoint vrací.
  5. Při kliknutí na tlačítko nejdříve získejte časovou zónu, kterou uživatel vybral z nabídky. Sestavte podle této hodnoty správnou URL. S výslednou URL zavolejte funkci fetch a získejte data o časové zǒně. Ve funkci, která zpracovává získaná data, zavolejte komponentu Time a zobrazte získaný čas na stránce.
6

Světový čas 2

zapni hlavu

Navažte na předchozí příklad se světovým časem. Naším cílem bude stáhnout seznam časových zón z API místo toho, abychom jej měli natvrdo zadrátovaný v HTML kódu.

Seznam časových zón stáhnete na adrese

https://worldtimeapi.org/api/timezone
  1. Vytvořte komponentu Timezones, který vytvoří obsah pro element zone-select. Tato komponenta bude očekávat props v tomto formátu:

    {
      zones: [
        // seznam zón
      ];
    }
    
  2. Otestujte vaši komponentu s nějakým vymyšleným seznamem zón abyste ověřili, že správně vytváří rozbalovací nabídku.

  3. Při načtení stránky zavolejte funkci fetch a stáhněte si skutečný seznam časových zón. Předejte jej komponentě Timezones.