Pracovat s webovým formulářem na straně JavaScriptu se poměrně snadno může stát očistcem. Nebo jak se nazývá ta věc na čištění záchodové mísy. Přitom za všechno může jedno nešťastné rozhodnutí.

Mějme jednoduchý formulář

<form id=myform>
	<input type=text name=query>
	<input type=submit value="Vyhledat">
</form>

K jeho jednotlivým prvkům přistoupíme přes vlastnost elements:

var form = document.getElementById('myform');
var query = form.elements.query.value;
// pochopitelně také form.elements['query'].value

A iterovat nad prvky lze cyklem for:

for (var i = 0; i < form.elements.length; i++) {
	alert(form.elements[i].value);
}

Z historických důvodů lze vlastnost elements v příkladech vynechat, neboť jednotlivé prvky se mapují přímo do objektu form. Takže by fungovalo i form.query.value, form.length nebo form[i].value. Což se záhy ukáže jako nemilé. Formulářové prvky totiž přepisují nativní metody a proměnné objektu form. Například metoda submit(), která je klíčová pro AJAXové odeslání formuláře, se stane nedostupnou, pokud formulář obsahuje prvek nazvaný submit. A uznejte, že to je zrovinka název pro odesílací tlačítko jako dělaný. Pokud by tedy formulář vypadal takto

<form id=myform>
	<input type=text name=query>
	<input type=submit name=submit value="Vyhledat">
</form>

nebude jej možné příkazem form.submit() odeslat, místo toho JavaScript zařve „form.submit is not a function“ a má pravdu, form.submit není funkce ale objekt HtmlInputElement. Dobrá, dáme si pozor a nebudeme formulářové prvky nazývat submit.

(prozradím trik, jak by formulář šlo odeslat i v tomto případě: document.createElement('form').submit.call(form))

Jenže název submit není tím jediným, kterému se musíme vyhnout. Prvek pojmenovaný elements způsobí, že form.elements nebude očekávaná kolekce a výše uvedené příklady skončí chybou. Název length zase znemožní nad kolekcí iterovat. A tak by se dalo pokračovat, nativních prvků třeba DOM Firefoxu definuje hodně přes stovku. Pro zajímavost uvádím seznam jen těch jednoslovných (tj. vynechávám nodeName nebo innerHTML):

action, attributes, blur, children, dir, draggable, elements, encoding, enctype, focus, id, lang, length, method, name, normalize, prefix, reset, spellcheck, style, submit, target, title

Bylo by skvělé, kdyby se HTML5 dokázalo s tímto nešvarem vypořádat. Zatím jsem ve specifikaci nic takového nenašel.

Podobně mi chybí možnost, jak v obsluze události onsubmit zjistit, kterým tlačítkem byl formulář odeslán. Triviální a užitečná věc a jak složitě se musí řešit.

<form id=myform onsubmit="kterým tlačítkem byl odeslán?">
	<input type=hidden name=id value="123">
	<input type=submit name=save value="Uložit">
	<input type=submit name=delete value="Smazat">
</form>

Řeším to tak, že odchytávám událost click jednotlivých tlačítek a název prvku ukládám do vlastní proměnné formuláře. O něco jednodušší je využít bublání a odchytávat click přímo na formuláři. Nicméně v HTML5 tohle už nebude fungovat spolehlivě, protože prvek může být umístěn i mimo strom formuláře a přiřazen k němu atributem form. Bylo by tedy fajn, kdyby HTML5 zavedlo vlastnost například form.submitter, který by vracela název odesílajícího tlačítka.

p. s. Nette Framework s těmito situacemi počítá a snaží se je v rámci možností řešit za programátora