Halloweenská akce! Na stránce s dobitím bodů zadej dole kód STRASIDELNYCH20 a získej porci +20% bodů zdarma!
Akce končí 31.10. o půlnoci.

Lekce 10 - Editor tabulek v JavaScriptu

JavaScript Základní konstrukce Editor tabulek v JavaScriptu American English version English version

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Manipulace s DOM v 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 v dnešním JavaScript tutoriálu 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 měli kód nějakým způsobem jednotný, protože v dalších JS lekcích budeme skript zdokonalovat, HTML stránka vypadá následovně. Všímejte si názvu souborů.

<!DOCTYPE html>
<html lang="cs">
        <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 vychoziVelikostY 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ř.:

let tabulka;
let vychoziVelikostX = 5;
let vychoziVelikostY = 3;

Později budeme potřebovat ještě jednu proměnnou, ale tou se nyní nebudeme zabývat. Vytvoříme funkce pro vygenerování ovládacích tlačítek a samotné tabulky. Funkci pro vygenerování tlačítek si necháme na později.

Funkce pro vytvoření tabulky (pojmenujeme si ji vytvorVychoziTabulku()) 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é v tabulce předpokládají označenou buňku, při označení buňky si tuto buňku musíme někam uložit. Existuje událost focus, která 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 událost tedy zároveň nově vytvořenému inputu obsloužíme a do proměnné aktivniBunka (kterou deklarujeme před deklarací funkce) buňku uložíme v případě, že je označená. 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).

let aktivniBunka;

function vytvorBunku() {
        let td = document.createElement("td");

        let 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. Nejprve se vrhneme na vytvoření samotné tabulky.

function vytvorVychoziTabulku() {
        tabulka = document.createElement("table");
        document.body.appendChild(tabulka);
}

Do proměnné tabulka uložíme nově vytvořený element <table> a ten vložíme do elementu <body>. Všimněte si, že když se chceme dostat k <body>, nemusíme složitě přes getElementsByTagName() nebo podobné, ale element je 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ž na to později zapomenout). Poté 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 předáme 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 (let y = 0; y < vychoziVelikostY; y++) {
                let tr = document.createElement("tr");
                tabulka.appendChild(tr);

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

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

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

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

Editor tabulek
localhost

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.

Editor tabulek
localhost

Další funkce

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 ...createElement("button"). Vytvoříme si na to funkci vytvorTlacitkoAVlozHo(). 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 zbytečně znepřehlednili zdrojový kód.

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

Nyní vytvoříme samotná tlačítka funkcím. Cílem tohoto projektu 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 vytvorOvladaciTlacitka(). 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 takto:

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 události window.onload:

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

Výsledek:

Editor tabulek
localhost

Přidat řádek

Začneme tím jednodušším – řádkem. Protože máme dvě funkce editoru, 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() {
        let novyRadek = document.createElement("tr");

        for (let 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.firstElementChild.childNodes.length a na první pohled jsme pouze schopni říci, že to má něco společného s tabulkou (table) a délkou (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.firstElementChild je element <tr>, childNodes jsou všechny elementy <td>, tedy pole elementů <td> a length je délka tohoto pole. Výsledkem tedy je, že table.firstElementChild.childNodes.length obsahuje 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.

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

Nebo si to nějak zjednodušeně poznamenáte formou komentáře, ať i příští rok víte co výraz znamená.

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

Můžete si zkusit procvičovat orientaci v kódu, jako ochutnávku si zkuste nějak promyslet co kde bude, když budeme mít tuto podmínku (v příští lekci tam skutečně bude):

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

V další lekci, Dokončení editoru tabulek v JavaScriptu, budeme pokračovat.


 

Stáhnout

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

 

 

Článek pro vás napsal Michal Žůrek - misaz
Avatar
Jak se ti líbí článek?
23 hlasů
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.
Miniatura
Předchozí článek
Manipulace s DOM v JavaScriptu
Miniatura
Všechny články v sekci
Základní konstrukce jazyka JavaScript
Aktivity (11)

 

 

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

Avatar
Tomáš Mořkovský:5. ledna 13:28

Zdravím,

v první část kódu mi v Atomu vůbec nejde zobrazit. Tabulka se zobrazí jen pokud kód začnu document,write(""), nevíte prosím někdo proč tomu tak je? předem díky.
přikládám svůj pokus:

document.write("E­ditor Tabulek")

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;

}
tabulka = document.crea­teElement("ta­ble")
document.body­.appendChild(ta­bulka)

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 5. ledna 13:28
Avatar
Tomáš Pour
Člen
Avatar
Tomáš Pour:6. června 20:25

Ahoj, zasekl jsem se téměř na začátku, kdy má Brackets problém hned s první řádkou aplikace...když změním "let" na "var", tak přeskočí error na další řádek a když změním všechny, tak mi to vypíše errorů hned několik...

 
Odpovědět 6. června 20:25
Avatar
Odpovídá na Tomáš Pour
Michal Žůrek - misaz:6. června 21:39

co to máš za vývojové prostředí? Funguje to v prohlížeči?

Odpovědět 6. června 21:39
Nesnáším {}, proto se jim vyhýbám.
Avatar
Tomáš Pour
Člen
Avatar
Odpovídá na Michal Žůrek - misaz
Tomáš Pour:6. června 22:23

Momentálně používám Brackets. V prohlížeči to právě nejde.

 
Odpovědět 6. června 22:23
Avatar
Odpovídá na Tomáš Pour
Michal Žůrek - misaz:6. června 23:30

tak dej F12 a podívej se co to napsalo za chybu.

Odpovědět 6. června 23:30
Nesnáším {}, proto se jim vyhýbám.
Avatar
Tomáš Pour
Člen
Avatar
Odpovídá na Michal Žůrek - misaz
Tomáš Pour:7. června 15:04

Tak ta chyba v prvním řádku je nejspíš nesmysl, ale když dám F12, tak mi to vypíše tohle:

 
Odpovědět 7. června 15:04
Avatar
Tomáš Pour
Člen
Avatar
Odpovídá na Michal Žůrek - misaz
Tomáš Pour:7. června 15:09

Tak už jsem přišel na chybu...měl jsem tam místo

tabulka.appendChild(tr);

tohle

document.appendChild(tr);

a ikdyž jsem to opravil, musel jsem promazat cache v Chrome.
Díky za pomoc :-)

 
Odpovědět 7. června 15:09
Avatar
Aleš Fišer
Člen
Avatar
Aleš Fišer:11. října 20:14

Ahoj , mám s tím jen jeden problém.Ta tlačítka se mi zobrazují místo nad tabulkou pod tabulkou.Nevíte v čem by mohl být problém?

Díky

 
Odpovědět 11. října 20:14
Avatar
Odpovídá na Aleš Fišer
Michal Žůrek - misaz:12. října 9:40

pokud postupuješ přesně podle tutoriálu, tak jsi možná prohodil řádky

vytvorOvladaciTlacitka();
vytvorVychoziTabulku();

Protože obě funkce přidávají elementy, tak se elementy logicky přidávají v takovém pořadí v jakém se volají funkce.

Odpovědět  +1 12. října 9:40
Nesnáším {}, proto se jim vyhýbám.
Avatar
Aleš Fišer
Člen
Avatar
Odpovídá na Michal Žůrek - misaz
Aleš Fišer:15. října 6:01

Děkuji ,problém byl přesně v tomto :)

 
Odpovědět 15. října 6:01
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 33. Zobrazit vše