10. díl - Editor tabulek v JavaScriptu

JavaScript Základní konstrukce Editor tabulek v JavaScriptu

V minulém tutoriálu o JavaScriptu jsme se naučili pracovat s DOM a měnit tak obsah stránky. Již umíme vše potřebné, abychom si vytvořili nějakou pravou webovou aplikaci. Jako příklad, na kterém se zároveň něco málo přiučíme, si naprogramujeme editor tabulek.

Tabulka je velmi zajímavý a specifický prvek webových stránek. Tabulka má řádky <tr> a buňky <td>. <td> náleží <tr> a <tr> náleží v nejjednodušším případě <table>.

HTML

Vytvořme si nějakou stránku, CSS soubor a JS soubor. CSS a JS do stránky v hlavičce naimportujeme a tím máme stránku hotovou, to že je body prázdné, nám spíše dokonce vyhovuje, protože si vše potřebné připravíme ve skriptu. Je to pro nás dokonce výhodné, nasadíme-li aplikaci na jiné stránce, nemusíme již vůbec zasahovat do HTML. Abychom to měli nějakým způsobem jednotné, protože v dalších dílech budeme skript zdokonalovat, má stránka vypadá následovně. Všímejte si názvu souborů.

<!DOCTYPE html>
<html lang="cs-CZ">
<head>
        <title>Editor tabulek</title>
        <meta charset="utf-8" />
        <script src="editor-tabulek.js"></script>
        <link href="editor-tabulek.css" rel="stylesheet" />
</head>
<body>

</body>
</html>

JavaScript

V souboru editor-tabulek.js si vytvoříme 3 proměnné. Proměnná tabulka bude obsahovat samotnou tabulku a poté budeme mít proměnné vychoziVelikostX a Y pro výchozí velikost tabulky. Tabulku necháme bez hodnoty a proměnným pro výchozí velikost dosadíme nějaká 2 kladná rozumně velká čísla. Např.

var tabulka
var vychoziVelikostX = 5
var vychoziVelikostY = 3

Později budeme potřebovat ještě jednu proměnnou, ale tou se nyní nebudeme zabývat. Vytvoříme funkce pro tvorbu ovládacích tlačítek a samotné tabulky. Funkce pro tlačítka nás zatím nemusí moc zajímat.

Funkce pro vytvoření tabulky (pojmenujeme si ji vytvorVychozi­Tabulku()) vytvoří tabulku a vloží ji do body. Dvěma vnořenými cykly vytvoříme její buňky. Aby byly buňky editovatelné, vložíme do nich klasické textové pole – element input. Protože buňky budeme vytvářet na více místech, vytvoříme si pro jejich tvorbu funkci vytvorBunku(). Ta vytvoří element <td> a <input>. Input vloží do <td> a buňku vrátí. Jelikož budeme programovat funkce, které potřebují jako výchozí bod označenou buňku, při označení buňky si ji musíme uložit. Obsluha události focus je vyvolána ve chvíli, kdy uživatel vybere nějaký prvek, ať již do něj klikne nebo se na něj třeba přesune tabulátorem. Při vytváření buňky ji tedy zároveň nově vytvořenému inputu obsloužíme a do proměnné aktivniBunka (kterou deklarujeme před deklarací funkce) uložíme ji. Je třeba pamatovat na to, že při obsluhování události se mění obsah klíčového slova this na prvek, který událost vyvolal. Do proměnné aktivniBunka uložíme právě this (což bude element input, protože on vyvolal událost).

var aktivniBunka;

function vytvorBunku() {
        var td = document.createElement("td")

        var tdInput = document.createElement("input")

        tdInput.type = "text"
        tdInput.onfocus = function () {
                aktivniBunka = this
        }
        td.appendChild(tdInput)

        return td;
}

Vraťme se k funkci, která vytvoří výchozí tabulku (za moment bude uvedena kompletní). Nejprve se vrhneme na vytvoření samotné tabulky.

tabulka = document.createElement("table")
document.body.appendChild(tabulka)

Do proměnné tabulka uložíme nově vytvořený element <table> a ten vložíme do objektu <body>. Sledujte, že když se chceme dostat k <body>, nemusíme složitě přes getElementsBy­TagName() nebo podobné, ale je to předpřipravené v document.body.

Nyní se podívejme na samotné cykly. Nejprve vytvoříme elementy řádku (cyklus Y) a každý nový řádek ihned vložíme do tabulky (ostatně vkládání je lepší vždy dělat dříve, než později zpětně něco složitě lovit) a pak vnořeným cyklem vytvoříme jednotlivé buňky a přidáme je do řádku. Využijeme k tomu metodu vytvorBunku(), kterou jsme si připravili před chvílí. Cyklům jako horní hodnoty nastavte proměnné vychoziVelikostX a vychoziVelikostY tak, aby se vytvořil správný počet řádků a sloupců.

function vytvorVychoziTabulku() {
        tabulka = document.createElement("table")
        document.body.appendChild(tabulka)
        for (var y = 0; y < vychoziVelikostY; y++) {
                var tr = document.createElement("tr")
                tabulka.appendChild(tr)

                for (var x = 0; x < vychoziVelikostX; x++) {
                        tr.appendChild(vytvorBunku())
                }
        }
}

Nyní již máme základ hotový. V obsluze události load na objektu window tuto funkci zavolejte.

window.onload = function () {
        vytvorVychoziTabulku();
}

Toto volání by vám již mělo být dobře známo. Jedná se o anonymní funkci přiřazenou do obsluhy události po načtení stránky. Když aplikaci spustíte, uvidíte tabulku (nejspíše bez ohraničení) a v ní inputy.

Základní tabulka

CSS

Gratuluji, vytvořili jste první aplikaci, která vygenerovala tabulku. Než se pustíme do další části, ostylujme si ji, ať vypadá trochu k světu. CSS nebudu popisovat. Pokud nějaké vlastnosti nerozumíte, naleznete ji popsanou v českém CSS 3 manuálu.

table {
        border-spacing:0;
        border: 1px solid black;
        width: 500px;
}
table, table td {
        padding:0;
        margin: 0;
}
table td {
        border: 1px solid black;
}
table td input {
        padding:0;
        margin: 0;
        width: 100%;
        border: 0px solid transparent;
        height: 100%;
}

Tabulka bude vypadat přibližně takto.

Ostylovaná tabulka

Další features

Nyní budeme implementovat další funkce našeho editoru. Půjdeme na to postupně. Aby naše funkce mohl uživatel používat, musíme mu přidat nějaké ovládací prvky, kterými je vyvolá. Prakticky jsem chtěl říci, že budeme potřebovat tlačítka :), ale teoreticky bychom mohli využít i jiných prvků.

Protože funkcí bude více, byl by nesmysl neustále psát …createElemen­t("button"). Vytvoříme si na to funkci – vytvorTlacitko­AVlozHo(). Návrhově správně by měla funkce dělat jednu věc a už podle názvu víme, že bude dělat dvě. Teoreticky bychom to mohli rozdělit na dvě funkce, ale dělali bychom to (a kopírovali kód) trochu zbytečně. Usuďte sami, zda vám přijde lepší varianta kopírovat část kódu nebo mít funkci, co dělá dvě věci. Funkce bude brát dva parametry - popisek a předka. Vytvoří tlačítko, nastaví mu popisek, vloží ho do předka a vrátí ho. Tlačítko vracíme jen kvůli tomu, abychom mu mohli nastavit obsluhu události. I tu bychom teoreticky mohli předat jako callback, ale tím bychom opět docela dost znepřehlednili kód.

function vytvorTlacitkoAVlozHo(popisek, rodic) {
        var btn = document.createElement("button")
        btn.textContent = popisek
        rodic.appendChild(btn)
        return btn
}

Nyní vytvoříme samotná tlačítka funkcím. Cílem tohoto dílu bude naprogramovat funkce pro přidání sloupce a řádku podle vybrané buňky (tu máme uloženou v proměnné aktivniBunka) a funkci pro odstranění řádku a sloupce. Vytvoříme si funkci vytvorOvladaci­Tlacitka(). Ve funkci budeme volat metodu pro vytvoření tlačítka. Vrácená tlačítka si ani nemusíme ukládat, protože obsluhu události můžeme přiřadit rovnou vrácené hodnotě. Prozatím si necháme tlačítka tak.

function vytvorOvladaciTlacitka() {
        vytvorTlacitkoAVlozHo("Přidat řádek dolů", document.body)
        vytvorTlacitkoAVlozHo("Přidat řádek nahoru", document.body)
        vytvorTlacitkoAVlozHo("Přidat sloupec vlevo", document.body)
        vytvorTlacitkoAVlozHo("Přidat sloupec vpravo", document.body)
        vytvorTlacitkoAVlozHo("Odstranit řádek", document.body)
        vytvorTlacitkoAVlozHo("Odstranit sloupec", document.body)
}

Funkci zavoláme v obsluze window.onload:

window.onload = function () {
        vytvorOvladaciTlacitka();
        vytvorVychoziTabulku();
}
Ovládací tlačítka editoru tabulek v JavaScriptu

Přidat řádek

Začneme tím jednodušším – řádkem. Protože budeme mít dvě funkce, které nějakým způsobem vytvoří řádek a někam ho vloží, napíšeme si funkci, která nám vytvoří element <tr> a vloží do něj tolik buněk, aby jich bylo jako u nějakého z již existujících řádků. Počet buněk bude nejjednodušší vzít hned z prvního řádku.

function vytvorRadek() {
        var novyRadek = document.createElement("tr")

        for (var i = 0; i < tabulka.firstElementChild.childNodes.length; i++) {
                novyRadek.appendChild(vytvorBunku())
        }
        return novyRadek;
}

Je třeba si uvědomit co je v které proměnné. Jako maximální hodnota pro i v cyklu je totiž table.firstEle­mentChild.chil­dNodes.length a na první pohled jsme pouze schopni říci, že to má něco společného s tabulkou (table) a počtem (length). Ostatní již na první pohled není až tak jasné. Ideální je, když si formou komentáře zapíšeme co kde je nebo si hodnoty postupně rozložíme do proměnných, ať se nám v zápisu lépe orientuje.

Element <table> má elementy <tr>. Víme tedy, že table.firstEle­mentChild je element <tr>, childNodes jsou všechny elementy element <td>, tedy pole elementů <td> a length je jejich počet. Výsledkem tedy je, že table.firstEle­mentChild.chil­dNodes.length vrátí počet buněk prvního řádku tabulky. Zápis je na vás, buď si to můžete postupně ukládat do proměnných.

var prvniRadek = tabulka.firstElementChild;
var bunkyPrvnihoRadku = prvniRadek.childNodes;
var pocetBunekVPrvnimRadku = bunkyPrvnihoRadku.length;

Nebo si to nějak zjednodušeně poznamenáte formou komentáře, ať i příští rok víte zhruba co by kde mělo být.

/*
 * table = <TABLE>
 * table.firstElementChild = <TR>
 * table.firstElementChild.childNodes = [<TD>]
 * table.firstElementChild.childNodes.length = number
 *
 * table.       firstElementChild.      childNodes      .length
 * <TABLE>.     <TR>.                   [<TD>]          .length
 */

V dalším dílu budeme pokračovat. Mezitím si můžete procvičovat orientaci v různém kódu jako ochutnávku si zkuste nějak popsat co kde bude, když budeme mít podmínku (v příštím dílu tam skutečně bude).

if (table.childNodes[i].childNodes[indexOfSelected] == table.childNodes[i].lastElementChild) { }

 

Stáhnout

Staženo 338x (1.88 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

  Aktivity (1)

Článek pro vás napsal Michal Žůrek (misaz)
Avatar
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.

Jak se ti líbí článek?
Celkem (10 hlasů) :
4.64.64.64.64.6


 


Miniatura
Předchozí článek
Manipulace s DOM v JavaScriptu
Miniatura
Všechny články v sekci
Základní konstrukce jazyka JavaScript

 

 

Komentáře
Zobrazit starší komentáře (11)

Avatar
Michal Žůrek (misaz):

Takové články nemůžeš číst od shora dolů, ale musíš je číst postupně, čemu nerozumíš si přečíst víckrát a hlavně si všechno zkoušet. Vůbec nevadí, že se u nějakého odstavce zasekneš třeba na půl hodiny. Cvičení se schvalují, pak si je zkus.

Odpovědět  +2 30.12.2014 9:12
Nesnáším {}, proto se jim vyhýbám.
Avatar
dr.jalo2
Člen
Avatar
dr.jalo2:

Rychle odtestovanie funkcie: vytvorRadek()

window.onload = function () {
    vytvorOvladaciTlacitka();
    vytvorVychoziTabulku();
    tabulka.appendChild(vytvorRadek());
}
 
Odpovědět 16.1.2015 14:28
Avatar
Odpovídá na Michal Žůrek (misaz)
Libor Šimo (libcosenior):

Michal, v niektorej z minulých častí tutoriálu som čítal, že stredníky sa nemusia používať, ale že sa aj tak používajú.
V tejto lekcii je to tak aj tak a myslím, že to trochu mýli.
Bolo by lepšie buď, aby tam neboli vôbec alebo všade, kde by mohli byť.

Odpovědět 15. dubna 8:23
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na Libor Šimo (libcosenior)
Michal Žůrek (misaz):

já jsem zvyklý z jazyků kde se nepoužívají a ovlivněn jazyky kde se používají. V JavaScript je klidně striktně piš všude, já to nějak intuitivně kombinuji.

Odpovědět 15. dubna 16:57
Nesnáším {}, proto se jim vyhýbám.
Avatar
romel999
Člen
Avatar
romel999:

Dobry den,

V prvním případě mi kód nefunguje a ve druhém případě, když jsem to zkopíroval tady z webu mi to jde.. Nemohu najít kde mám chybu. Děkuji za pomoc

var tabulka
var vychoziVelikostX = 5
var vychoziVelikostY = 3

var aktivniBunka;

function vytvorBunku() {
var td = document.crea­teElement("td")

var tdInput = document.crea­teElement("in­put")

tdInput.type = "text"
tdInput.onfocus = function () {
aktivniBunka = this
}
td.appendChil­d(tdInput)

return td;
}

function vytvorVychozi­Tabulku() {
tabulka = document.crea­teElement("ta­ble")
document.body­.appendChild(ta­bulka)
for (var y = 0; y < vychoziVelikostY; y++) {
var tr = document.crea­teElement("tr")
tabulka.appen­dChild(tr)

for (var x = 0; x < vychoziVelikostX; x++) {
tr.appendChil­d(vytvorBunku())
}
}
}

window.onload = function () {
vytvorVyhoziTa­bulku();
}
_____________­________________________­________________________­_________________

var tabulka
var vychoziVelikostX = 5
var vychoziVelikostY = 3

var aktivniBunka;

function vytvorBunku() {
var td = document.crea­teElement("td")

var tdInput = document.crea­teElement("in­put")

tdInput.type = "text"
tdInput.onfocus = function () {
aktivniBunka = this
}
td.appendChil­d(tdInput)

return td;
}

function vytvorVychozi­Tabulku() {
tabulka = document.crea­teElement("ta­ble")
document.body­.appendChild(ta­bulka)
for (var y = 0; y < vychoziVelikostY; y++) {
var tr = document.crea­teElement("tr")
tabulka.appen­dChild(tr)

for (var x = 0; x < vychoziVelikostX; x++) {
tr.appendChil­d(vytvorBunku())
}
}
}

window.onload = function () {
vytvorVychozi­Tabulku();
}

 
Odpovědět 13. listopadu 10:05
Avatar
Libor Šimo (libcosenior):

Vypis uje ti to chybu v conzole?

Odpovědět 13. listopadu 15:18
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na romel999
Michal Žůrek (misaz):

na předposledním řádku máš překlep. Místo vychozi tam máš jenom h

vytvorVyhoziTabulku(); // tvoje
vytvorVychoziTabulku(); // správně
Odpovědět 13. listopadu 16:55
Nesnáším {}, proto se jim vyhýbám.
Avatar
Odpovídá na Michal Žůrek (misaz)
Libor Šimo (libcosenior):

Conzola by mu riadok s chybou urcite oznacila.

Odpovědět 13. listopadu 18:15
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovědět 13. listopadu 18:16
Nesnáším {}, proto se jim vyhýbám.
Avatar
Odpovídá na Michal Žůrek (misaz)
Libor Šimo (libcosenior):

Jasne, aj ja som sa najprv pokusil najst chybu v texte, lebo to bolo jasne.
Problem je ale v ludskom mozgu.
Nejrozsirenajsi
precitas ako
Nejrozsirenejsi
a nevsimnes si chybu.
Preto som vdacny za prekladace a IDE.

Odpovědět  +1 13. listopadu 18:34
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 21. Zobrazit vše