NOVINKA: Kurz kybernetické bezpečnosti s akreditací MŠMT, nyní již od 0 Kč. Staň se žádaným profesionálem. Zjisti více:
NOVINKA: Staň se datovým analytikem a získej jistotu práce, lepší plat a nové kariérní možnosti. Více informací:

Lekce 14 - AJAX v JavaScriptu - Prohlížeč pokémonů

V minulé lekci, AJAX v JavaScriptu - Základní dotazy, jsme si zkusili základní použití technologie AJAX na našem novém projektu prohlížeče pokémonů. Stáhli jsme si data o pokémonech z webového API.

V dnešním tutoriálu OOP v JavaScriptu budeme pokračovat s tvorbou prohlížeče pokémonů pomocí AJAXu.

Odpověď serveru

Zaměřme se nyní na vrácená data ve formátu JSON. Odpověď serveru vypadá následovně. Už jsme ji sice viděli, ale zde si ji zkrátíme a lépe naformátujeme:

{
    "count":1350,
    "next":"https://pokeapi.co/api/v2/pokemon?offset=20&limit=20",
    "previous":null,
    "results":
    [
        {"name":"bulbasaur","url":"https://pokeapi.co/api/v2/pokemon/1/"},
        {"name":"ivysaur","url":"https://pokeapi.co/api/v2/pokemon/2/"},
        ...,
        {"name":"raticate","url":"https://pokeapi.co/api/v2/pokemon/20/"}
    ]
}

První položka (count) na vráceném objektu udává celkový počet záznamů, které má endpoint k dispozici. Nejvíce nás zajímá pole results, kde jsou objekty se jmény pokémonů a adresami na API s jejich detaily. Jak to, že je v poli pouze 20 pokémonů, když jich je víc jak 1300? Není to chyba. Tento endpoint totiž vrací jen prvních 20 pokémonů, aby zbytečně nezatěžoval server. V položce next nám navíc nabídne URL, která načte 20 následujících pokémonů. Uživateli obvykle nepotřebujeme zobrazit 1350 položek najednou. API proto počítá s tím, že je budeme načítat průběžně, například při scrollování stránky dolů. Pokud bychom chtěli stáhnout všechny pokémony, musíme upravit parametr limit v URL: https://pokeapi.co/api/v2/pokemon?limit=1350.

V praxi ale většinou načítáme data po částech, protože je to šetrnější k serveru i k uživateli.

Prohlížeč pokémonů

Nyní tedy umíme stahovat data a je jen na nás, jak s nimi naložíme. Pojďme si naprogramovat jednoduchý prohlížeč pokémonů.

Funkce stahniJSON()

Budeme již dělat více requestů, proto si to zjednodušíme novou funkcí stahniJSON(). Náš dosavadní kód v souboru obsluha.js tedy smažeme a přidáme si definici nové funkce stahniJSON():

function stahniJSON(url, callback)
{
    const xhr = new XMLHttpRequest();
    xhr.onload = () => {
        callback(JSON.parse(xhr.response));
    };
    xhr.open("GET", url);
    xhr.send();
}

Funkce obsahuje vytvoření, otevření a odeslání požadavku, abychom stejný kód nemuseli psát opakovaně. Přijímá dva parametry:

  • url – Adresa, ze které chceme stáhnout data.
  • callback – Funkce, kterou voláme po úspěšném stažení dat ze serveru. Stažená data této funkci předáváme parametrem.

Všimněme si parsování JSON do objektu pomocí JSON.parse(), protože odpovědí serveru je text.

Funkce stahniJSON() vůbec neřeší selhání požadavku. Pro jednoduchost jsme prozatím obsluhu chyb vynechali, věnujeme se jí v příští lekci.

HTML kostra

Připravíme si základní HTML kostru stránky, do které budeme AJAXem stahovat seznam pokémonů a následně dokonce zobrazovat detaily vybraného pokémona, včetně jeho obrázku :) Budeme tedy potřebovat jeden <div> pro seznam pokémonů a jeden pro detaily jednoho pokémona. Oba obalíme třetím elementem <div> a vložíme na začátek elementu <body> souboru index.html:

<div id="poke-container">
    <div id="poke-seznam"></div>
    <div id="poke-detaily"></div>
</div>

Načítání pokémonů

Nyní budeme potřebovat další dvě funkce – nactiSeznam() a nactiPokemona(), které stáhnou data a přepíšou obsah na stránce. Pojďme si je naprogramovat.

Načtení seznamu

Do souboru obsluha.js tedy vložíme další funkci nactiSeznam() s následujícím kódem:

function nactiSeznam(url) {
    const seznamDivElement = document.getElementById("poke-seznam");
    seznamDivElement.innerHTML = "<ul id='poke-seznam-ul'></ul>";
    const seznamElement = document.getElementById("poke-seznam-ul");

    stahniJSON(url, (data) => {
        for (const pokemon of data.results) {
            const urlPokemona = pokemon.url;

            const tlacitko = document.createElement("button");
            tlacitko.innerHTML = pokemon.name;
            tlacitko.onclick = () => {
                nactiPokemona(urlPokemona);
            };

            const novaPolozka = document.createElement("li");
            novaPolozka.appendChild(tlacitko);
            seznamElement.appendChild(novaPolozka);
        }
    });
}

Funkce v parametru přijímá adresu API, ze kterého budeme stahovat data. V těle funkce si nejprve vytváříme element seznamu, do kterého pokémony vypíšeme. Jde o základní práci s DOM elementy. Samotné pokémony následně stahujeme pomocí naší funkce stahniJSON(). Té předáváme adresu API a anonymní funkci, která se zavolá po úspěšném stažení dat.

Tato anonymní funkce má pouze jeden parametr s objektem obsahujícím stažená data. Pokémoni jsou obsaženi ve vlastnosti results. Pole pokémonů procházíme cyklem a pro každého vytváříme položku seznamu <li> do které vložíme tlačítko. Každému tlačítku přidáváme obsluhu události onclick, ve které voláme funkci nactiPokemona() s URL daného pokémona (získané z dat API).

Každé API odpovídá v jiném formátu, takže si vždy musíme zjistit, jak s vrácenými daty pracovat.

Načtení detailu pokémona

Podívejme se, jak vypadá JSON s detailem nějakého pokémona, což nám osvětlí, jaká data přenést do naší aplikace. Kvůli všem útokům pokémona a jejich detailům je JSON opravdu vyčerpávající, pro naše účely si tyto části uvádět nebudeme, níže jsou nahrazeny třemi tečkami ...:

{
    "abilities": [
        ...
    ],
    "base_experience": 64,
    "forms": [
        ...
    ],
    "game_indices": [
        ...
    ],
    "height": 7,
    "held_items": [],
    "id": 1,
    "is_default": true,
    "location_area_encounters": "https://pokeapi.co/api/v2/pokemon/1/encounters",
    "moves": [
        ...
            ]
        }
    ],
    "name": "bulbasaur",
    "order": 1,
    "species": {
        "name": "bulbasaur",
        "url": "https://pokeapi.co/api/v2/pokemon-species/1/"
    },
    "sprites": {
        "back_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/1.png",
        "back_female": null,
        "back_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/shiny/1.png",
        "back_shiny_female": null,
        "front_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png",
        "front_female": null,
        "front_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/1.png",
        "front_shiny_female": null
    },
    "stats": [
        ...
    ],
    "types": [
        {
            "slot": 2,
            "type": {
                "name": "poison",
                "url": "https://pokeapi.co/api/v2/type/4/"
            }
        },
        {
            "slot": 1,
            "type": {
                "name": "grass",
                "url": "https://pokeapi.co/api/v2/type/12/"
            }
        }
    ],
    "weight": 69
}

Výše vidíme JSON pro Bulbasaura, konkrétně stažený z URL https://pokeapi.co/api/v2/pokemon/1/, kde parametr 1 udává číslo pokémona. Zajímá nás zejména vlastnost name s názvem pokémona, sprites s jeho obrázky, height s výškou a weight s váhou daného pokémona. Mohli bychom vypsat i typy pokémona. U Bulbasaura například vidíme, že je travního a jedovatého typu.

bulbasaur - Objektově orientované programování v JavaScriptu

Podobně jako seznam, i detail pokémona stáhneme jednoduchou funkcí. V souboru obsluha.js si tedy vytvoříme funkci posílající dotaz na konkrétního pokémona s následujícím kódem:

function nactiPokemona(url) {
    const detailyDivElement = document.getElementById("poke-detaily");

    stahniJSON(url, (data) => {
        detailyDivElement.innerHTML = `
            <img src="${data.sprites.front_default}" />
            <ul>
                <li>Název: ${data.name}</li>
                <li>Výška: ${data.height}</li>
                <li>Váha: ${data.weight}</li>
            </ul>
        `;
    });
}

Zavolání načtení seznamu

Vše máme připraveno. Stačí již jen jako poslední řádek našeho JavaScriptového souboru zavolat načtení seznamu:

nactiSeznam("https://pokeapi.co/api/v2/pokemon");

CSS styly

Aby náš prohlížeč vypadal lépe, přidáme ještě několik CSS stylů. Ve složce css/ si vytvoříme soubor styly.css s následujícím kódem:

#poke-container {
    display: flex;
    gap: 2rem;
}

#poke-detaily {
    text-align: center;
    margin-left: 10px;
}

#poke-container ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
}

#poke-seznam li button {
    width: 100%;
    padding: 5px 20px;
    background-color: #e0ffe0;
    cursor: pointer;
    border: 0;
    border-bottom: 1px solid green;
}

#poke-seznam li button:hover {
    background-color: green;
}

Nezapomeneme si je samozřejmě nalinkovat v hlavičce souboru index.html:

<head>
    <meta charset="UTF-8">
    <title>Prohlížeč pokémonů</title>
    <link href="css/styly.css" rel="stylesheet">
</head>

Interaktivní ukázka

Výsledek bude vypadat takto:

Prohlížeč pokémonů
localhost

Po kliknutí na položku se načtou základní informace o pokémonovi a obrázek.

Tím ale možnosti API s pokémony opravdu nekončí :) Jak sami vidíte, API pokémonů je velmi chytré a všude nám nabízí další URL, přes které se dostaneme k dalším datům, třeba k abilitám.

V příští lekci, AJAX v JavaScriptu - POST a další HTTP dotazy, pošleme AJAX požadavky pro ukládání a zpracování dat a ukážeme si jak zpracovat chyby.


 

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 361x (2.86 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

Předchozí článek
AJAX v JavaScriptu - Základní dotazy
Všechny články v sekci
Objektově orientované programování v JavaScriptu
Přeskočit článek
(nedoporučujeme)
AJAX v JavaScriptu - POST a další HTTP dotazy
Článek pro vás napsal Radek Veverka
Avatar
Uživatelské hodnocení:
265 hlasů
Jsem student VUT FIT v třetím ročníku. Nejraději mám Typescript a C#.
Aktivity