Na navigaci | Klávesové zkratky

Translate to English… Ins Deutsche übersetzen…

Formuláře a HTML5 - co mi ještě chybí

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

Komentáře

  1. Daniel Steigerwald #1

    avatar

    Zjistit tlačítko lze. Ne však pomocí čistého Javascriptu, protože form eventy: submit, focus, blur a reset nebublají. Kdyby jo, použil bys jednoduše event.target.
    Chytřejší javascriptové knihovny (a jQuery) tohle řeší. Pro focus/blur použijí eventy náhradní nebo capture fázy. Tohle však u submit ani reset použít nelze. Interně to třeba jQuery řeší tak, že po registraci $(‚form‘).live(‚submit‘, fn') skutečně odchytává click, pak no následně volá na všech parentech, a tím simuluje bublání.
    Mají tam však bug, takže i když submit buble, a currentTarget funguje, tak target se korektně nastaví pouze v IE. Chtěl sem jim napsat fix, ale musel sem se spokojit s nahlášením bugu, protože sem po ruce neměl potřebný „očistec“.
    Shrnuto, nativně to HTML5 řešit nemůže, protože to je zpětně kompatibilní pragmatická „specifikace“ (na rozdíl od idealistické XHTML2).
    Řeší to však knihovny, a jQuery ten bug dříve či později opraví též.

    před 6 lety | reagoval [9] David Grudl
  2. Daniel Steigerwald #2

    avatar

    Co se týká prvku elements a mapování names na form, mám pocit že jde o prehistorický pozůstatek DOM0.
    Koukám teď, že nejenom YUI3 ale i jQuery zcela zbytečně tuto prehistorickou kolekci stále používají. jQuery v metodě http://api.jquery.com/serializeArray/
    Mootools například elements nikdy nepoužívali. Serializovat přeci můžeš libovolný element, obsahující formulářové prvky. Mimochodem, výstup té jQuery metody je dost nepraktický, raději z formuláře vyrobím objekt http://pastie.org/1088700, a ten pak pošlu na server jako JSON, kde se mi nabinduje na existující třídy. Plochá querystring struktura je na prd, pokud chceš na server odeslat celé objektové grafy.
    V Nette bych pak místo .elements použil .getElementsByTagName(‚*‘). Šlape to všude a žádného přepisování se není třeba obávat.
    Co se týká mapování na form. O tom vím, ale nikdy sem to neřešil, protože sem nikdy nepoužíval syntetický submit (nepíšu weby, ale aplikace). Triku pomocí call bych se bál, ale pokud to funguje všude, nech to tak. (jen je třeba to testovat)

    před 6 lety
  3. Daniel Steigerwald #3

    avatar

    Jestli chceš vidět dobrou implementaci (třeba pro inspiraci pro Nette), mrkni se na http://github.com/…ini/nwevents

    před 6 lety
  4. vojta #4

    Je to drobnost, ale všechny atributy HTML prvků by měly být v uvozovkách, kodéra to dráždí! :-)

  5. Jan Tichý http://www.phpguru.cz #5

    avatar

    #4 vojto, Neměly. (Ajajaj, to bude zase flame.)

    před 6 lety
  6. Patrik Votoček http://patrik.votocek.cz #6

    avatar

    #4 vojto, Neměly. Ale můžou.

    před 6 lety
  7. v6ak http://v6ak.profitux.cz #7

    Ono by to asi šlo řešit bez úderu do zpětné kompatibility. Ale, na druhou stranu, dost hnusně. Mám pocit, že je možné nějakému objektů přiřadit ekvivalent __call. (Na phpfashion mi asi budete rozumět.)
    Víte, kam mířím? Mohly by tu být metody jako getAction(), getLength() apod. Pokud by někdo čistě náhodou použil takto blbý název, dostal by onen element ono „__call“. Ale, na druhou stranu, pokud by takový element měl svoje id (například), šlo by třeba odesílat formulář pomocí document.getElementById(„foo“)(), měl-li bych <button type="submit" name="submit" id="foo">Odeslat. Takže, je to trošku vyhánění satana ďáblem.

    před 6 lety
  8. David Grudl http://davidgrudl.com #8

    avatar

    #4 vojto, do uvozovek dávají atributy jen méněcenní kodéři a tlusté ženy!

    před 6 lety | reagoval [10] vojta
  9. David Grudl http://davidgrudl.com #9

    avatar

    #1 Danieli Steigerwalde, Dane, stačí právě probublávání click a tím pádem to řešit lze.

    před 6 lety
  10. vojta #10

    #8 Davide Grudle, „Always Quote Attribute Values
    Attribute values should always be enclosed in quotes
    http://www.w3schools.com/…tributes.asp
    Jestli je tady kroužek opozice vůči standardům, mělo by to být uvedeno v hlavičce webu ;-)

    před 6 lety | reagoval [11] David Grudl
  11. David Grudl http://davidgrudl.com #11

    avatar

    #10 vojto, w3schools.com není standard, ale web soukromé společnosti. Standard najdeš tady nebo tady.

    před 6 lety | reagoval [12] vojta
  12. vojta #12

    #11 Davide Grudle, OK. Díky za odkazy. Na prvním místě se používání uvozovek výslovně vyžaduje, na druhém se připouští i zápis bez nich. Nevím tedy, jak někteří přišli na to že by se uvozovky psát „neměly“.
    Opravdu mi připadá čistší zápis
    <a href="#" title="Klikni na mě" name="odkaz123" id="odkaz123" />
    než
    <a href="#" title="Klikni na mě" name=odkaz123 id=odkaz123 />
    a vůbec nerozumím, proč nekonzistentní 2. verzi zápisu někdo považuje za „méněcennou“. Osobně v ní vidím samé nevýhody a divím se, že se nikomu neekluje míchání názvu proměnné s její hodnotou. Zdar.

    před 6 lety | reagoval [13] vojta
  13. vojta #13

    #12 vojto, Davide, teď vidím, že tvůj vlastní parser automaticky přidává hodnotám atributů uvozovky (v mém původním příspěvku u 2. odkazu nejsou uvozovky u atributů name a id).
    Tak tohle je dokonalý vlastňák :-D :-D

    před 6 lety | reagoval [14] David Grudl
  14. David Grudl http://davidgrudl.com #14

    avatar

    #13 vojto, upravil jsem tvůj komentář, aby tam uvozovky nebyly. Obě HTML specifikace připouštějí možnost za určitých okolností uvozovky vynechat, čti pozorněji. A také tu nikdo neříkal, že by se psát neměly. Tohle téma prosím uzavřeme.

    před 6 lety
  15. v6ak http://v6ak.profitux.cz/ #15

    Taky jsem pro, sice tu už asi nebude živá diskuze, ale myslím, že tato diskuze jen odvádí pozornost od tématu.

    před 6 lety

Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.