3. března 2026

Modifikace dokumentu

Klíčem k vytváření „živých“ stránek je modifikace DOMu.

Zde uvidíme, jak vytvářet nové elementy „za běhu“ a jak modifikovat obsah existující stránky.

Příklad: zobrazení zprávy

Předveďme si to na příkladu. Přidáme na stránku zprávu, která bude vypadat lépe než alert.

Bude to vypadat následovně:

<style>
.upozornění {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

<div class="upozornění">
  <strong>Nazdar!</strong> Právě čteš důležitou zprávu.
</div>

To byl příklad v HTML. Nyní vytvořme stejný div v JavaScriptu (předpokládáme, že styly jsou již definovány v HTML/CSS).

Vytvoření elementu

K vytvoření DOM uzlu slouží dvě metody:

document.createElement(značka)

Vytvoří nový elementový uzel se zadanou značkou:

let div = document.createElement('div');
document.createTextNode(text)

Vytvoří nový textový uzel se zadaným textem:

let textovýUzel = document.createTextNode('Tady jsem');

Většinou potřebujeme vytvářet elementové uzly, například div pro naši zprávu.

Vytvoření zprávy

Vytvoření značky div pro zprávu se skládá ze tří kroků:

// 1. Vytvoříme element <div>
let div = document.createElement('div');

// 2. Nastavíme jeho třídu na "upozornění"
div.className = "upozornění";

// 3. Vložíme do něj obsah
div.innerHTML = "<strong>Nazdar!</strong> Právě čteš důležitou zprávu.";

Vytvořili jsme element. Prozatím se však nachází jen v proměnné jménem div a ne na stránce, takže ho nemůžeme vidět.

Metody pro vkládání

Aby se nám div ukázal, musíme ho vložit někam do document, například do elementu <body>, na který se odkazuje document.body.

K tomu slouží speciální metoda append: document.body.append(div).

Zde je celý kód:

<style>
.upozornění {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

<script>
  let div = document.createElement('div');
  div.className = "upozornění";
  div.innerHTML = "<strong>Nazdar!</strong> Právě čteš důležitou zprávu.";

  document.body.append(div);
</script>

Tady jsme volali append na document.body, ale metodu append můžeme volat i na kterémkoli jiném elementu, abychom do něj vložili další element. Můžeme například něco připojit k <div> voláním div.append(dalšíElement).

Existují i další vkládací metody, které specifikují jiná místa, kam se má vkládat:

  • uzel.append(...uzly nebo řetězce) – připojí uzly nebo řetězce na konec uzlu uzel,
  • uzel.prepend(...uzly nebo řetězce) – vloží uzly nebo řetězce na začátek uzlu uzel,
  • uzel.before(...uzly nebo řetězce) –- vloží uzly nebo řetězce před uzel,
  • uzel.after(...uzly nebo řetězce) –- vloží uzly nebo řetězce za uzel,
  • uzel.replaceWith(...uzly nebo řetězce) –- nahradí uzel zadanými uzly nebo řetězci.

Argumenty těchto metod je jakýkoli seznam DOM uzlů, které se mají vložit, nebo textových řetězců (z nich se automaticky vytvoří textové uzly).

Podívejme se na ně v akci.

Následuje příklad, jak pomocí těchto metod přidat prvky do seznamu a text před a za něj:

<ol id="ol">
  <li>0</li>
  <li>1</li>
  <li>2</li>
</ol>

<script>
  ol.before('před'); // vloží řetězec "před" před <ol>
  ol.after('za'); // vloží řetězec "za" za <ol>

  let liPrvní = document.createElement('li');
  liPrvní.innerHTML = 'začátek';
  ol.prepend(liPrvní); // vloží liPrvní na začátek <ol>

  let liPoslední = document.createElement('li');
  liPoslední.innerHTML = 'konec';
  ol.append(liPoslední); // vloží liPoslední na konec <ol>
</script>

Na obrázku je zobrazeno, co tyto metody dělají:

Výsledný seznam tedy bude:

před
<ol id="ol">
  <li>začátek</li>
  <li>0</li>
  <li>1</li>
  <li>2</li>
  <li>konec</li>
</ol>
za

Jak bylo uvedeno, tyto metody dokáží vložit více uzlů a částí textu při jednom volání.

Například zde se vloží řetězec a element:

<div id="div"></div>
<script>
  div.before('<p>Ahoj</p>', document.createElement('hr'));
</script>

Prosíme všimněte si, že text se vloží „jako text“, ne „jako HTML“, takže znaky jako < a > budou příslušným způsobem upraveny.

Výsledný HTML kód tedy je:

&lt;p&gt;Ahoj&lt;/p&gt;
<hr>
<div id="div"></div>

Jinými slovy, řetězce se vloží bezpečným způsobem stejně, jak to dělá elem.textContent.

Tyto metody tedy můžeme použít jedině ke vkládání DOM uzlů a částí textu.

Ale co když chceme vložit HTML řetězec „jako html“, aby v něm fungovaly všechny značky a všechno ostatní, stejně, jak to provádí elem.innerHTML?

insertAdjacentHTML/Text/Element

K tomu můžeme použít jinou, víceúčelovou metodu: elem.insertAdjacentHTML(kam, html).

Prvním parametrem je kódové slovo, které specifikuje, kam se má vkládat, relativně vůči elem. Musí to být jedno z následujících:

  • "beforebegin" – vloží html bezprostředně před elem,
  • "afterbegin" – vloží html do elem na začátek,
  • "beforeend" – vloží html do elem na konec,
  • "afterend" – vloží html bezprostředně za elem.

Druhým parametrem je HTML řetězec, který bude vložen „jako HTML“.

Příklad:

<div id="div"></div>
<script>
  div.insertAdjacentHTML('beforebegin', '<p>Ahoj</p>');
  div.insertAdjacentHTML('afterend', '<p>Sbohem</p>');
</script>

…Vytvoří:

<p>Ahoj</p>
<div id="div"></div>
<p>Sbohem</p>

Tímto způsobem můžeme ke stránce připojit libovolný HTML kód.

Varianty vkládání jsou znázorněny na obrázku:

Snadno si všimneme podobností mezi tímto a předchozím obrázkem. Místa pro vkládání jsou ve skutečnosti stejná, ale tato metoda vkládá HTML kód.

Tato metoda má dvě sesterské metody:

  • elem.insertAdjacentText(kam, text) – stejná syntaxe, ale řetězec text se místo HTML vloží „jako text“,
  • elem.insertAdjacentElement(kam, elem) – stejná syntaxe, ale vloží element.

Tyto metody existují hlavně proto, aby syntaxe byla „jednotná“. V praxi se většinou používá jen insertAdjacentHTML, protože pro elementy a text máme metody append/prepend/before/after – jsou kratší na napsání a umějí vkládat uzly nebo části textu.

Zde je tedy alternativní varianta zobrazení zprávy:

<style>
.upozornění {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

<script>
  document.body.insertAdjacentHTML("afterbegin", `<div class="upozornění">
    <strong>Nazdar!</strong> Právě čteš důležitou zprávu.
  </div>`);
</script>

Odstranění uzlu

K odstranění uzlu slouží metoda uzel.remove().

Nechme naši zprávu za jednu sekundu zmizet:

<style>
.upozornění {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

<script>
  let div = document.createElement('div');
  div.className = "upozornění";
  div.innerHTML = "<strong>Nazdar!</strong> Právě čteš důležitou zprávu.";

  document.body.append(div);
  setTimeout(() => div.remove(), 1000);
</script>

Prosíme všimněte si, že jestliže chceme přemístit element na jiné místo, nemusíme jej z původního místa odstraňovat.

Všechny vkládací metody automaticky odstraní uzel z místa, kde se nacházel předtím.

Například prohoďme elementy navzájem:

<div id="první">První</div>
<div id="druhý">Druhý</div>
<script>
  // není třeba volat remove
  druhý.after(první); // vezme #druhý a za něj vloží #první
</script>

Klonování uzlů: cloneNode

Jak vložit další podobnou zprávu?

Mohli bychom vytvořit funkci a vložit kód do ní. Alternativním způsobem však je klonovat existující div a změnit text uvnitř něj (pokud to potřebujeme).

Někdy, když máme velký element, to může být rychlejší a jednodušší.

  • Volání elem.cloneNode(true) vytvoří „hluboký“ klon elementu – se všemi atributy a podelementy. Jestliže zavoláme elem.cloneNode(false), bude klon vytvořen bez dětských elementů.

Příklad kopírování zprávy:

<style>
.upozornění {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

<div class="upozornění" id="div">
  <strong>Nazdar!</strong> Právě čteš důležitou zprávu.
</div>

<script>
  let div2 = div.cloneNode(true); // naklonujeme zprávu
  div2.querySelector('strong').innerHTML = 'Sbohem!'; // změníme klon

  div.after(div2); // zobrazíme klon za existujícím <div>
</script>

DocumentFragment

DocumentFragment je speciální DOM uzel, který slouží jako obal pro předávání seznamů uzlů.

Můžeme k němu přidávat další uzly, ale když jej někam vložíme, místo něj se vloží jeho obsah.

Například následující funkce vraťObsahSeznamu vygeneruje fragment s prvky <li>, které jsou následně vloženy do <ul>:

<ul id="ul"></ul>

<script>
function vraťObsahSeznamu() {
  let fragment = new DocumentFragment();

  for(let i=1; i<=3; i++) {
    let li = document.createElement('li');
    li.append(i);
    fragment.append(li);
  }

  return fragment;
}

ul.append(vraťObsahSeznamu()); // (*)
</script>

Prosíme všimněte si, že na posledním řádku (*) jsme připojili DocumentFragment, ale ten „vymizí“ a výsledná struktura bude následující:

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ul>

DocumentFragment se explicitně používá jen zřídka. Proč bychom měli něco připojovat ke speciálnímu druhu uzlu, když místo něj můžeme vrátit pole uzlů? Přepsaný příklad:

<ul id="ul"></ul>

<script>
function vraťObsahSeznamu() {
  let výsledek = [];

  for(let i=1; i<=3; i++) {
    let li = document.createElement('li');
    li.append(i);
    výsledek.push(li);
  }

  return výsledek;
}

ul.append(...vraťObsahSeznamu()); // append + operátor "..." = přátelé!
</script>

Zmínili jsme DocumentFragment hlavně proto, že na něm jsou postaveny určité koncepty, například element šablony, který probereme mnohem později.

Vkládací a odebírací metody ze staré školy

Stará škola
Tato informace pomáhá porozumět starým skriptům, ale pro nový vývoj není potřebná.

Existují i metody pro manipulaci s DOMem „ze staré školy“, které jsou zachovány z historických důvodů.

Tyto metody pocházejí z mnohem dřívější doby. V současnosti není důvod je používat, jelikož moderní metody, např. append, prepend, before, after, remove, replaceWith, jsou flexibilnější.

Jediným důvodem, proč zde tyto metody uvádíme, je, že je můžete najít v mnoha starých skriptech:

rodičovskýElement.appendChild(uzel)

Připojí uzel jako poslední dítě elementu rodičovskýElement.

Následující příklad přidá nový <li> na konec <ol>:

<ol id="seznam">
  <li>0</li>
  <li>1</li>
  <li>2</li>
</ol>

<script>
  let novýLi = document.createElement('li');
  novýLi.innerHTML = 'Ahoj, světe!';

  seznam.appendChild(novýLi);
</script>
rodičovskýElement.insertBefore(uzel, dalšíSourozenec)

Vloží uzel před uzel dalšíSourozenec do elementu rodičovskýElement.

Následující kód vloží nový prvek seznamu před druhý <li>:

<ol id="seznam">
  <li>0</li>
  <li>1</li>
  <li>2</li>
</ol>
<script>
  let novýLi = document.createElement('li');
  novýLi.innerHTML = 'Ahoj, světe!';

  seznam.insertBefore(novýLi, seznam.children[1]);
</script>

Chceme-li vložit novýLi jako první element, můžeme to udělat následovně:

seznam.insertBefore(novýLi, seznam.firstChild);
rodičovskýElement.replaceChild(uzel, původníDítě)

Nahradí původníDítě mezi dětmi elementu rodičovskýElement uzlem uzel.

rodičovskýElement.removeChild(uzel)

Odstraní uzel z elementu rodičovskýElement (za předpokladu, že uzel je jeho dítětem).

Následující příklad odstraní první <li> z <ol>:

<ol id="seznam">
  <li>0</li>
  <li>1</li>
  <li>2</li>
</ol>

<script>
  let li = seznam.firstElementChild;
  seznam.removeChild(li);
</script>

Všechny tyto metody vracejí vložený nebo odstraněný uzel. Jinými slovy, rodičovskýElement.appendChild(uzel) vrátí uzel. Návratová hodnota se však obvykle nepoužívá, prostě jen zavoláme metodu.

Pár slov o „document.write“

Existuje ještě jedna, velice stará metoda pro přidávání na webovou stránku: document.write.

Syntaxe:

<p>Někde na stránce...</p>
<script>
  document.write('<b>Pozdrav od JS</b>');
</script>
<p>Konec</p>

Volání document.write(html) zapíše html na stránku „právě tady a teď“. Řetězec html může být dynamicky generován, takže metoda je do určité míry flexibilní. Můžeme v JavaScriptu vytvořit webovou stránku obsahující vše potřebné a zapsat ji.

Tato metoda pochází ještě z doby, kdy neexistoval žádný DOM, žádné standardy… Z opravdu dávné doby. Stále však existuje, protože jsou skripty, které ji využívají.

V moderních skriptech ji vidíme jen zřídka, a to kvůli následujícímu důležitému omezení:

Volání document.write funguje jen tehdy, dokud se stránka načítá.

Pokud ji zavoláme později, stávající obsah dokumentu bude smazán.

Příklad:

<p>Po jedné sekundě bude obsah této stránky nahrazen...</p>
<script>
  // document.write po 1 sekundě
  // tedy po načtení této stránky, takže existující obsah se smaže
  setTimeout(() => document.write('<b>...Tímto.</b>'), 1000);
</script>

Ve stavu „po načtení“ je tedy víceméně nepoužitelná, na rozdíl od ostatních DOM metod, které jsme tady probrali.

To je její nevýhoda.

Má však i výhodu. Technicky, když je document.write zavolána a něco zapíše, zatímco prohlížeč načítá („parsuje“) přicházející HTML kód, prohlížeč to zpracuje tak, jako by to bylo v původním HTML kódu.

Funguje tedy bleskově rychle, protože se nekoná žádná modifikace DOMu. Zapisuje rovnou do textu stránky, dokud ještě DOM není vytvořen.

Pokud tedy potřebujeme dynamicky přidat do HTML velké množství textu, nacházíme se ve fázi načítání stránky a záleží nám na rychlosti, tato metoda nám může pomoci. V praxi však tyto požadavky málokdy přicházejí současně. A ve skriptech tuto metodu vidíme převážně proto, že jsou prostě staré.

Shrnutí

  • Metody pro vytváření nových uzlů:

    • document.createElement(značka) – vytvoří element se zadanou značkou,
    • document.createTextNode(hodnota) – vytvoří textový uzel (používá se málokdy),
    • elem.cloneNode(hluboce) – naklonuje element, pokud hluboce==true, pak se všemi potomky.
  • Vkládání a odstraňování:

    • uzel.append(...uzly nebo řetězce) – vloží do uzel na jeho konec,
    • uzel.prepend(...uzly nebo řetězce) – vloží do uzel na jeho začátek,
    • uzel.before(...uzly nebo řetězce) – vloží bezprostředně před uzel,
    • uzel.after(...uzly nebo řetězce) – vloží bezprostředně za uzel,
    • uzel.replaceWith(...uzly nebo řetězce) – nahradí uzel,
    • uzel.remove() – odstraní uzel.

    Textové řetězce se vkládají „jako text“.

  • Existují i metody „ze staré školy“:

    • rodič.appendChild(uzel)
    • rodič.insertBefore(uzel, dalšíSourozenec)
    • rodič.removeChild(uzel)
    • rodič.replaceChild(novýElement, uzel)

    Všechny tyto metody vracejí uzel.

  • Máme-li nějaký HTML kód v proměnné html, pak jej elem.insertAdjacentHTML(kam, html) vloží na místo, které závisí na hodnotě kam:

    • "beforebegin" – vloží html bezprostředně před elem,
    • "afterbegin" – vloží html do elem na jeho začátek,
    • "beforeend" – vloží html do elem na jeho konec,
    • "afterend" – vloží html bezprostředně za elem.

    Existují i podobné metody elem.insertAdjacentText a elem.insertAdjacentElement, které vkládají textové řetězce a elementy, ale používají se jen zřídka.

  • Pro připojení HTML kódu ke stránce, ještě než skončilo její načítání:

    • document.write(html)

    Po dokončení načítání stránky toto volání smaže dokument. K vidění převážně ve starých skriptech.

Úlohy

důležitost: 5

Máme prázdný DOM element elem a řetězec text.

Které z těchto tří příkazů provedou přesně totéž?

  1. elem.append(document.createTextNode(text))
  2. elem.innerHTML = text
  3. elem.textContent = text

Odpověď zní: 1 a 3.

Oba příkazy mají za následek přidání textu text „jako text“ do elementu elem.

Zde je příklad:

<div id="elem1"></div>
<div id="elem2"></div>
<div id="elem3"></div>
<script>
  let text = '<b>text</b>';

  elem1.append(document.createTextNode(text));
  elem2.innerHTML = text;
  elem3.textContent = text;
</script>
důležitost: 5

Vytvořte funkci vyčisti(elem), která z elementu odstraní všechen obsah.

<ol id="elem">
  <li>Ahoj</li>
  <li>světe</li>
</ol>

<script>
  function vyčisti(elem) { /* váš kód */ }

  vyčisti(elem); // vyčistí seznam
</script>

Nejprve se podíváme, jak to nedělat:

function vyčisti(elem) {
  for (let i=0; i < elem.childNodes.length; i++) {
      elem.childNodes[i].remove();
  }
}

To nebude fungovat, protože volání remove() posune prvky v kolekci elem.childNodes, takže elementy budou pokaždé začínat od indexu 0. Avšak i se zvýší a některé elementy tedy budou přeskočeny.

Cyklus for..of dělá totéž.

Správná varianta může být:

function vyčisti(elem) {
  while (elem.firstChild) {
    elem.firstChild.remove();
  }
}

A existuje i jednodušší způsob, jak udělat totéž:

function vyčisti(elem) {
  elem.innerHTML = '';
}
důležitost: 1

V následujícím příkladu volání tabulka.remove() odstraní tabulku z dokumentu.

Pokud si ho však spustíte, uvidíte, že text "aaa" je stále viditelný.

Proč se tak děje?

<table id="tabulka">
  aaa
  <tr>
    <td>Test</td>
  </tr>
</table>

<script>
  alert(tabulka); // tabulka, jak by měla vypadat

  tabulka.remove();
  // proč je v dokumentu stále „aaa“?
</script>

Důvodem této podivnosti je, že HTML kód v tomto úkolu je nekorektní.

Prohlížeč ho musí automaticky opravit. Uvnitř <table> však nesmí být žádný text: podle specifikace jsou povoleny jen značky specifické pro tabulku. Prohlížeč tedy zobrazí "aaa" před <table>.

Nyní je jasné, proč zůstane, i když tabulku odstraníme.

Na tuto otázku lze snadno odpovědět po prozkoumání DOMu prohlížečovými nástroji. Uvidíte "aaa" před <table>.

Standard HTML podrobně specifikuje, jak se má zpracovávat vadný HTML, a tak je toto chování prohlížeče korektní.

důležitost: 4

Napište uživatelské rozhraní, které vytvoří seznam z uživatelského vstupu.

Pro každý prvek seznamu:

  1. Zeptejte se uživatele na jeho obsah pomocí prompt.
  2. Vytvořte značku <li>, která ho bude obsahovat, a přidejte ji do <ul>.
  3. Pokračujte, dokud uživatel nezruší vstup (stisknutím klávesy Esc nebo prázdným vstupem).

Všechny elementy by měly být vytvářeny dynamicky.

Jestliže uživatel zadá HTML značky, mělo by se s nimi zacházet jako s textem.

Demo v novém okně

Prosíme, všimněte si, že k přiřazení obsahu <li> je použit textContent.

Otevřít řešení na pískovišti.

důležitost: 5

Napište funkci vytvořStrom, která z vnořeného objektu vytvoří vnořený seznam ul/li.

Například:

let data = {
  "Ryby": {
    "pstruh": {},
    "losos": {}
  },

  "Stromy": {
    "Velké": {
      "sekvoj": {},
      "dub": {}
    },
    "Kvetoucí": {
      "jabloň": {},
      "magnólie": {}
    }
  }
};

Syntaxe:

let kontejner = document.getElementById('kontejner');
vytvořStrom(kontejner, data); // vytvoří strom v kontejneru

Výsledek (strom) by měl vypadat takto:

Zvolte si jeden ze dvou způsobů, jak tento úkol vyřešit:

  1. Vytvořte HTML kód stromu a přiřaďte jej do kontejner.innerHTML.
  2. Vytvořte uzly stromu a připojujte je DOM metodami.

Pokud dokážete obojí, bude to vynikající.

P.S. Strom by neměl obsahovat elementy „navíc“, například prázdné <ul></ul> pro listy.

Otevřít pískoviště pro úlohu.

Nejjednodušší způsob, jak procházet objektem, je používat rekurzi.

  1. Řešení pomocí innerHTML.
  2. Řešení pomocí DOMu.
důležitost: 5

Máme strom, organizovaný jako vnořené ul/li.

Napište kód, který ke každému <li> přidá počet jeho potomků. Listy (uzly bez dětí) přeskakujte.

Výsledek:

Otevřít pískoviště pro úlohu.

Abychom do každé značky <li> připojili text, můžeme změnit textový uzel data.

Otevřít řešení na pískovišti.

důležitost: 4

Napište funkci vytvořKalendář(elem, rok, měsíc).

Její volání by mělo vytvořit kalendář pro zadaný rok a měsíc a vložit jej do elementu elem.

Kalendářem by měla být tabulka, v níž bude týden představovat značka <tr> a den značka <td>. V záhlaví tabulky by měla být značka <th> s názvy dnů v týdnu: prvním dnem by mělo být pondělí a tak dále, až do neděle.

Například vytvořKalendář(kal, 2012, 9) by v elementu kal mělo vytvořit následující kalendář:

P.S. V této úloze postačí vytvořit kalendář, nemusí reagovat na klikání.

Otevřít pískoviště pro úlohu.

Vytvoříme tabulku jako řetězec: "<table>...</table>" a pak ji přiřadíme do innerHTML.

Algoritmus:

  1. Vytvoříme záhlaví tabulky se značkou <th> a názvy dnů v týdnu.
  2. Vytvoříme objekt s datem d = new Date(rok, měsíc-1). To je první den v měsíci měsíc (bereme v úvahu, že měsíce v JavaScriptu začínají od 0, ne od 1).
  3. Několik prvních buněk před prvním dnem v měsíci d.getDay() může být prázdných. Vyplníme je značkami <td></td>.
  4. Zvýšíme den v d: d.setDate(d.getDate()+1). Pokud d.getMonth() ještě není další měsíc, přidáme do kalendáře další buňku <td>. Pokud je to neděle, přidáme nový řádek “</tr><tr>” .
  5. Pokud měsíc skončil, ale řádek tabulky ještě není zcela zaplněný, přidáme do něj prázdné <td>, abychom dokončili čtverec.

Otevřít řešení na pískovišti.

důležitost: 4

Vytvořte barevné hodiny, jako jsou tyto:

Styly nastavte pomocí HTML/CSS, JavaScript bude jen aktualizovat čas v elementech.

Otevřít pískoviště pro úlohu.

Nejprve vytvořme HTML/CSS.

Každá komponenta hodin bude vypadat skvěle ve svém vlastním <span>:

<div id="hodiny">
  <span class="hod">hh</span>:<span class="min">mm</span>:<span class="sec">ss</span>
</div>

Budeme také potřebovat CSS k jejich obarvení.

Funkce aktualizuj bude aktualizovat hodiny, aby ji funkce setInterval mohla každou sekundu volat:

function aktualizuj() {
  let hodiny = document.getElementById('hodiny');
  let datum = new Date(); // (*)
  let hod = datum.getHours();
  if (hod < 10) hod = '0' + hod;
  hodiny.children[0].innerHTML = hod;

  let minuty = datum.getMinutes();
  if (minuty < 10) minuty = '0' + minuty;
  hodiny.children[1].innerHTML = minuty;

  let sekundy = datum.getSeconds();
  if (sekundy < 10) sekundy = '0' + sekundy;
  hodiny.children[2].innerHTML = sekundy;
}

Na řádku (*) pokaždé zjistíme aktuální datum, protože volání setInterval nejsou spolehlivá: může k nim docházet s prodlevami.

Funkce pro správu hodin:

let idČasovače;

function spusťHodiny() { // spustí hodiny
  if (!idČasovače) { // nový interval nastavíme, jen pokud hodiny neběží
    idČasovače = setInterval(aktualizuj, 1000);
  }
  aktualizuj(); // (*)
}

function zastavHodiny() {
  clearInterval(idČasovače);
  idČasovače = null; // (**)
}

Prosíme všimněte si, že volání aktualizuj() není jen nastaveno ve spusťHodiny(), ale spustí se okamžitě na řádku (*). Jinak by návštěvník musel čekat do prvního spuštění setInterval a hodiny by do té doby byly prázdné.

Je také důležité nastavit nový interval ve funkci spusťHodiny() jen tehdy, když hodiny neběží. Jinak by několik kliknutí na spouštěcí tlačítko nastavilo více souběžných intervalů. Ještě horší by bylo, že bychom si pamatovali jen idČasovače posledního intervalu a ztratili odkazy na všechny ostatní. Pak bychom už nikdy nedokázali hodiny zastavit! Všimněte si, že když jsou na řádku (**) hodiny zastaveny, musíme idČasovače smazat, abychom mohli hodiny znovu spustit voláním spusťHodiny().

Otevřít řešení na pískovišti.

důležitost: 5

Napište kód, který vloží <li>2</li><li>3</li> mezi tyto dvě značky <li>:

<ul id="ul">
  <li id="jedna">1</li>
  <li id="dvě">4</li>
</ul>

Když potřebujeme někam vložit část HTML kódu, je nejlepší volbou insertAdjacentHTML.

Řešení:

jedna.insertAdjacentHTML('afterend', '<li>2</li><li>3</li>');
důležitost: 5

Máme následující tabulku:

<table>
<thead>
  <tr>
    <th>Jméno</th><th>Příjmení</th><th>Věk</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td>Jan</td><td>Novák</td><td>10</td>
  </tr>
  <tr>
    <td>Petr</td><td>Horák</td><td>15</td>
  </tr>
  <tr>
    <td>Anna</td><td>Králová</td><td>5</td>
  </tr>
  <tr>
    <td>...</td><td>...</td><td>...</td>
  </tr>
</tbody>
</table>

Může obsahovat další řádky.

Napište kód, který ji seřadí podle sloupce "jméno".

Otevřít pískoviště pro úlohu.

Řešení je krátké, ale může vypadat trochu komplikovaně, proto je opatřím rozsáhlými komentáři:

let seřazenéŘádky = Array.from(tabulka.tBodies[0].rows) // 1
  .sort((rowA, rowB) => rowA.cells[0].innerHTML.localeCompare(rowB.cells[0].innerHTML));

tabulka.tBodies[0].append(...seřazenéŘádky); // (3)

Algoritmus krok za krokem:

  1. Získáme z <tbody> všechny značky <tr>.
  2. Pak je seřadíme podle obsahu první značky <td> (pole se jménem).
  3. Nyní vložíme uzly ve správném pořadí pomocí .append(...seřazenéŘádky).

Nemusíme elementy řádků odstraňovat, stačí je „znovu vložit“ a z původního umístění se odstraní automaticky.

P.S. V našem případě je v tabulce explicitně uvedeno <tbody>, ale i kdyby HTML tabulka <tbody> neobsahovala, DOM struktura je vždy bude mít.

Otevřít řešení na pískovišti.

Mapa tutoriálu

Komentáře

přečtěte si před komentováním…
  • Máte-li návrhy na zlepšení, vytvořte prosím issue na GitHubu nebo pull request místo komentáře.
  • Pokud v článku něčemu nerozumíte, napište prosím, čemu přesně a na kterém místě.
  • Pro vložení několika slov kódu použijte značku <code>, pro několik řádků je obalte značkou <pre>, pro více než 10 řádků vložte odkaz na pískoviště (plnkr, jsbin, codepen…)