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.
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
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ť:
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