Dynamické skrývání prvků ve formuláři
Chcete zobrazit políčka pro zadání adresy, pouze pokud chce uživatel zaslat zboží poštou? Žádný problém :).
Metody addCondition()
& toggle()
Klíčem k triku s dynamickým zobrazováním políček je dvojice metod addCondition()
&
toggle()
. Příklad z perexu by s jejich využitím mohl vypadat například takto:
$form->addCheckbox('mail_me')
->addCondition($form::EQUAL, true)
->toggle();
$form->addText('city');
$form->addText('street');
$form->addText('zipcode');
Metoda addCondition()
umí přijímat stejné argumenty jako základní validační metoda addRule()
,
kromě toho, že nepodporuje žádnou chybovou hlášku. V ukázkovém kódu výše tedy volání doslova znamená „pokud je
tento prvek zaškrtnutý“. Metoda toggle()
může vždy následovat až po volání
addCondition()
.
Naše ukázka je však zatím nekompletní, metoda toggle()
totiž vyžaduje argument: měla by jím být hodnota
id
atributu ve výsledném HTML kódu – element s tímto IDčkem pak bude dynamicky odhalen/skryt právě
v závislosti na podmínce definované v addCondition()
.
Jak získat ID pro toggle()
Vypadá to, že formulář budeme muset vyrenderovat manuálně, pomocí maker {form}
, {label}
a
{input}
, resp. n:name
. V šabloně bychom pak mohli zapsat třeba takovýto kód:
<div id="address-container">
{label city /} {input city}<br>
{label street /} {input street}<br>
{label zipcode /} {input zipcode}
</div>
A volání v definici formuláře bychom doplnili následovně:
$form->addCheckbox('mail_me')
->addCondition($form::EQUAL, true)
->toggle('address-container');
A je to. Pokud máme v šabloně přilinkovaný soubor netteForms.js
, políčka se budou ihned dynamicky
objevovat v závislosti na zaškrtnutí checkboxu.
Jak se vyhnout manuálnímu renderování
Nutnost manuálně vykreslovat formulář může být často velmi otravná – například pokud máte v administraci
spoustu velmi podobných formulářů. Pokud používáte DefaultFormRenderer
, umí naštěstí framework podat
pomocnou ruku. Stačí totiž prvkům nastavit zvláštní option id
, která bude ve výsledku vykreslena jako ID
atribut elementu obalujícího jak <label>
, tak <input>
, tedy přesně to, co potřebujeme.
V praxi vypadá použití následovně:
$form->addCheckbox('mail_me')
->addCondition($form::EQUAL, true)
->toggle('address-city')
->toggle('address-street')
->toggle('address-zipcode');
$form->addText('city')
->setOption('id', 'address-city');
$form->addText('street')
->setOption('id', 'address-street');
$form->addText('zipcode')
->setOption('id', 'address-zipcode');
Proč jsme nemohli všem prvkům nastavit stejnou option id
a zjednodušit si tak volání toggle
?
V HTML správně nesmí být více prvků se stejným ID. JavaScript by se pak s takovou situací špatně vyrovnával.
Je také vhodné zmínit, že metoda toggle()
má druhý nepovinný parametr, kterým lze obrátit její
chování. Pokud bychom zavolali ->toggle('address-city', false)
, políčko pro zadání města by se naopak
zobrazilo pouze tehdy, pokud by checkbox zaškrtnutý nebyl.
Možná jste někde zahlédli metodu setHtmlId
, kterou lze libovolnému formulářovému prvku nastavit ID. Ta se
však pro naše účely nehodí, protože se nijak nedotýká odpovídajícího <label>
– popisek by zůstal
viditelný.
Jak přidat animaci
Výchozí implementace toggle()
v prohlížeči využívá pouhého nastavení CSS vlastnosti
display: none
, s čímž žádnou velkou parádu neuděláme. Přidání animace však není problém. Stačí
v Javascriptu přepsat metodu Nette.toggle
vlastním řešením. S využitím jQuery pak třeba můžeme políčka
pro adresu nechat přirolovat:
Nette.toggle = function (id, visible) {
var el = $('#' + id);
if (visible) {
el.slideDown();
} else {
el.slideUp();
}
};