IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

11. diel - Dokončenie editora tabuliek v JavaScripte

V minulej lekcii, Editor tabuliek v JavaScripte , sme rozpracovali editor tabuliek. V dnešnom JavaScript tutoriálu túto webovú aplikáciu dokončíme.

Index riadku aktívnej bunky

Aby sme si techniky "orientovanie sa" v premenných DOM osvojili, napíšeme si 2 funkcie, ktoré neskôr využijeme. Jednou z nich je funkcia indexRadkuAktivniBunky(), ktorá vráti index riadku (poradí od nuly), kde sa nachádza užívateľom vybrané bunky (aktivniBunka). Najprv si treba uvedomiť, kde tento index získame. Hľadáme medzi riadkami tabuľky. Tabuľka je predstavovaná elementom <table> a riadky sú ihneď v ňom (bunky sú až v riadkoch, čo môže miasť, dávajte si na to pozor).

Kde budeme hľadať: tabulka.childNodes

A čo hľadáme, bude to trochu zložitejšie. Hľadáme riadok, ale my vieme, že v aktivniBunka nie je element <td>, ale <input>, ktorý je v <td>. Aby sme sa dostali na <td>, musíme z bunky dostať parentElement a ani to nám nebude stačiť. Nepotrebujeme bunku, ale riadok a ten opäť získame pomocou parentElement.

Čo hľadáme: aktivniBunka.parentElement.parentElement

NodeList a indexOf ()

Ak si spomínate, tak v minulej JS lekcii som spomenul, že funkcia s DOM nikdy nevracia poľa, ale NodeList alebo podobné špecializované kolekcie. A že tieto objekty sú len (prakticky) hlúpejší poľa. Bohužiaľ NodeList nemá metódu indexOf(), ktorá by nám vrátila potrebný index prvku. Sú dva varianty. Prvá je, že si ho cyklom proiterujeme sami a druhá je, že použijeme metódu indexOf() na objekte Array a zavoláme ju s kontextom NodeListu. Druhú časť predchádzajúceho súvetí dôkladne pochopíte u objektovo orientovaného programovania. Zatiaľ nám stačí vedieť, že zavoláme indexOf() na poli, ale "podvrhneme" mu NodeList. JavaScriptu je totiž jedno s čím pracuje, ak to má všetko čo má mať a NodeList túto vlastnosť spĺňa. Metódy sa volajú so zmeneným kontextom tak, že ich nájdeme v prototypu objektu (v našom prípade Array.prototype) a zavoláme na ne metódu call(). Ako prvý parameter ju odovzdáme nový kontext a za ne pridáme parametre metódy.

Výsledný kód by tak mohol vyzerať nasledovne:

function indexRadkuAktivniBunky() {
    let cilHledani = tabulka.childNodes;
    let hledanyPrvek = aktivniBunka.parentElement.parentElement;
    return Array.prototype.indexOf.call(cilHledani, hledanyPrvek);
}

V cilHledani máme to, v čom hľadáme. V hledanyPrvek máme čo hľadáme. V cilHledani je NodeList a hledanyPrvek je element <tr>. Potom vrátime hodnotu, ktorú vráti indexOf(), načo ju zmeníme kontext na NodeList a ako parameter, ktorý má bežne, odovzdáme onen element <tr>.

Index stĺpca aktívnej bunky

O niečo jednoduchšie to bude so získavaním indexu stĺpca aktívnej bunky. Potrebujeme sa dostať k riadku, kde sa bunka nachádza a získať jej pozíciu. Bunku opäť dostaneme pomocou parentElement na aktivniBunka a na riadku, ktorému patrí cez parentElement.parentElement.

function indexSloupceAktivniBunky() {
    let bunkyVRadku = aktivniBunka.parentElement.parentElement.childNodes;
    let td = aktivniBunka.parentElement;
    return Array.prototype.indexOf.call(bunkyVRadku, td);
}

Doteraz to možno bolo trochu nudné, pretože sa nič zaujímavého nedialo. Teraz to však bude zaujímavejšie. Už konečne začneme programovať funkcie pre ovládanie aplikácie.

Pridanie riadku nad vybraný

Metódu, ktorá vytvára nový riadok (element <tr>), máme už hotovú. Vieme získať index riadku, na ktorom leží vybraná bunka, a vieme nový riadok aj vložiť. Pre prehľadnosť si nový riadok uložíme do premennej, index riadku rovnako tak a opäť sa budeme prehrabávať DOM. Riadky (<tr>) sú vnorené priamo v elemente tabuľky (<table>), takže to bude jednoduché. Metódu insertBefore() voláme na tabuľke. Prvý parameter je jasný, to je nový riadok. Druhý parameter musí byť <tr>, v ktorom je vložená aktívna bunka. Ďalej sa prepracovávať nemusíme, riadky sú priamo v tabuľke, preto rovno z NodeListu vyberieme riadok podľa indexu riadku aktívnej bunky.

function pridejRadekNahoru() {
    let radek = vytvorRadek();
    let indexVybraneho = indexRadkuAktivniBunky();
    tabulka.insertBefore(radek, tabulka.childNodes[indexVybraneho]);
}

Vo funkcii, ktorá vytvára ovládacie tlačidlá, obsluhe tlačidlu pre pridanie riadku hore udalosť onclick.

vytvorTlacitkoAVlozHo("Pridať riadok hore", document.body).onclick = pridejRadekNahoru;

Teraz sa pustíme do trochu silnejší kávy, ale vlastne to nebude nič nové.

Pridávanie riadku za vybraný

Tu budeme postupovať prakticky rovnako, ale doplatíme opäť na to, že JavaScript neobsahuje žiadnu metódu insertAfter() a my budeme musieť riadok vkladať pred aktuálne + 1, aby sme ho dostali na správnu pozíciu. Pamätajme, že pri tom ešte musíme ošetrovať, či takto nevkladáme za posledný, pretože riadok posledná + 1 neexistuje. Použijeme podmienku na zistenie, či je posledný element tabuľky (tabulka.lastChild) rovný riadku, v ktorom je vybraná aktuálna bunka. Ak je, tak vkladáme nakoniec jednoducho metódou appendChild(). V opačnom prípade vložíme riadok pomocou insertBefore() pred riadok za riadkom s vybranou bunkou.

function pridejRadekDolu() {
    let radek = vytvorRadek();
    let indexVybraneho = indexRadkuAktivniBunky();
    if (tabulka.lastChild == tabulka.childNodes[indexVybraneho]) {
        tabulka.appendChild(radek);
    } else {
        tabulka.insertBefore(radek, tabulka.childNodes[indexVybraneho + 1]);
    }
}

Nastavte obsluhu udalosti danému tlačidlu:

vytvorTlacitkoAVlozHo("Pridať riadok nadol", document.body).onclick = pridejRadekDolu;

Teraz už vieme pridávať riadky rôzne do tabuľky, kde sa nám hodí. Funkcionalitu si môžete vyskúšať v živej ukážke nižšie, nezabudnite však predtým označiť nejakú bunku tabuľky kliknutím do nej.

Editor tabuliek
localhost

Pridanie stĺpce vľavo

Pridanie stĺpca už bude zložitejšie. Tabuľka v HTML totiž obsahuje riadky a v tých sú bunky. A ajhľa, v kóde nie sú žiadne stĺpce! Pridanie stĺpca budeme musieť teda riešiť tak, že pridáme bunku do existujúcich riadkov. Cyklom prejdeme všetky riadky tabuľky a do každého riadku pred index vybrané bunky vložíme novú bunku.

Teraz je potrebné si uvedomiť čo je kde a čo budeme kde potrebovať. Budeme vkladať do riadku <tr> a ten je v <table>. Výraz tabulka.childNodes vracia pole riadkov <tr> a my musíme vkladať v cykle do každého z nich novú bunku.

Kam vkladáme: tabulka.childNodes[i]

Vkladáme novú bunku.

Čo vkladáme: vytvorBunku()

A teraz pred čo. Referenčná element (ten, pred ktorý vkladáme) musí byť vnútri elementu, kam vkladáme. Jednoducho teda začneme tým, že odovzdáme ten istý element, do ktorého vkladáme. Pretože je to element zvnútra, logicky ho nájdeme vnútri NodeList u childNodes a vieme, že tento childNodes je pole prvkov buniek <td> (Hurá! Ty hľadáme!). Index teda (ktorý je pre daný cyklus konštantný) bude onen index bunky medzi stĺpci. Ak ste sa vo výklade stratili, skúste si to prejsť nižšie v kóde.

Pred čo vkladáme: tabulka.childNodes[i].childNodes[indexVybraneho]

Celé to bude vyzerať nasledovne.

function pridejSloupecDoleva() {
    let indexVybraneho = indexSloupceAktivniBunky();
    for (let i = 0; i < tabulka.childNodes.length; i++) {
        tabulka.childNodes[i].insertBefore(vytvorBunku(), tabulka.childNodes[i].childNodes[indexVybraneho]);
    }
}

Ak vám to prišlo zložité alebo neprehľadné, tak ako sa pustíte do ďalšej časti (pretože tá je k orientácii ešte o niečo ťažšie), doplňte si vhodne komentáre alebo si kód rozdeľte do rozumne pomenovaných premenných.

Pridanie stĺpce vpravo

Ako už asi tušíte, bude to podobné, len sa musíme opäť vyrovnať s chýbajúce metódou insertAfter() ako sme to urobil v metóde pridejRadekDolu(). Jediným rozdielom (opäť) je, že musíme overiť, že nevkladáme na koniec. Logicky dôjdeme k tomu, že overujeme vždy to, čo vkladáme s posledným elementom rodičia overovaniu elementu.

function pridejSloupecDoprava() {
    let indexVybraneho = indexSloupceAktivniBunky();
    for (let i = 0; i < tabulka.childNodes.length; i++) {
        if (tabulka.childNodes[i].childNodes[indexVybraneho] == tabulka.childNodes[i].lastElementChild) {
            tabulka.childNodes[i].appendChild(vytvorBunku());
        } else {
            tabulka.childNodes[i].insertBefore(vytvorBunku(), tabulka.childNodes[i].childNodes[indexVybraneho + 1]);
        }
    }
}

Pridajme obsluhy udalostí tlačidlám pre pridávanie stĺpcov a aplikáciu vyskúšajte.

vytvorTlacitkoAVlozHo("Pridať stĺpec vľavo", document.body).onclick = pridejSloupecDoleva;
vytvorTlacitkoAVlozHo("Pridať stĺpec vpravo", document.body).onclick = pridejSloupecDoprava;

Aplikáciu vyskúšajte. Po náročnej práci si môžete zahrať napríklad piškvorky vo vašej tabuľke. Jednoducho si pridajte veľa stĺpcov a riadkov :)

Editor tabuliek
localhost

Možno pri používaní aplikácie narazíme na problém. Tabuľka môže mať o stĺpec alebo riadok viac, než sme chceli. Pridáme funkcie pre mazanie riadku a stĺpca.

Mazanie riadku

Z tabuľky odstránime riadok, ktorého element dostaneme tak, že zoberieme všetky elementy tabuľky (childNodes) a vyberieme ten s indexom vybranej bunky.

function smazRadek() {
    let indexVybraneho = indexRadkuAktivniBunky();
    tabulka.removeChild(tabulka.childNodes[indexVybraneho]);
}

Mazanie stĺpce

Mazanie stĺpca musíme zabezpečiť tak, že zmažeme v každom riadku (cyklom) bunku, ktorej index zodpovedá indexu vybranej bunky.

function smazSloupec() {
    let indexVybraneho = indexSloupceAktivniBunky();
    for (let i = 0; i < tabulka.childNodes.length; i++) {
        tabulka.childNodes[i].removeChild(tabulka.childNodes[i].childNodes[indexVybraneho]);
    }
}

Sprevádzkujeme tlačidlá a máme hotovo.

vytvorTlacitkoAVlozHo("Odstrániť riadok", document.body).onclick = smazRadek;
vytvorTlacitkoAVlozHo("Odstrániť stĺpec", document.body).onclick = smazSloupec;

Aplikáciu si môžete vyskúšať:

Editor tabuliek
localhost

Po tomto príklade by ste už mali ovládať DOM v JavaScripte. Všetka tá kúzla od vytvárania tabuľky až po piškvorky boli vlastne len hříčky s niekoľkými málo elementy, ktoré by sme bežne písali v HTML. Všimnite si, že na začiatku všetkého máme HTML kód, ktorý v body nemá jediný element.

V budúcej lekcii, Striktné operátormi a pretypovanie v JavaScripte , si povieme ešte niečo o podmienkach, než sa pustíme do ďalšieho väčšieho témy - práca s grafikou.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 1813x (2.11 kB)
Aplikácia je vrátane zdrojových kódov v jazyku JavaScript

 

Predchádzajúci článok
Editor tabuliek v JavaScripte
Všetky články v sekcii
Základné konštrukcie jazyka JavaScript
Preskočiť článok
(neodporúčame)
Striktné operátormi a pretypovanie v JavaScripte
Článok pre vás napísal Michal Žůrek - misaz
Avatar
Užívateľské hodnotenie:
3 hlasov
Autor se věnuje tvorbě aplikací pro počítače, mobilní telefony, mikroprocesory a tvorbě webových stránek a webových aplikací. Nejraději programuje ve Visual Basicu a TypeScript. Ovládá HTML, CSS, JavaScript, TypeScript, C# a Visual Basic.
Aktivity