Obsah
Nette\Application\AppForm
Třída AppForm je navržena speciálně pro použití v presenteru – má obslužné mechanismy na zpracování signálů. Od třídy Form se liší také tím, že má převrácené argumenty v konstruktoru (Form má jako první argument jméno a až jako druhý rodičovský IComponentContainer). Třída Form má parametr $parent uvedený až „bokem“ proto, že tam, kde se používá, obvykle žádný parent není potřeba a ani neexistuje.
AppForm využívá ke svému zpracování handlery. Ty se zpracovávají ve fázi zpracování signálů životního cyklu presenteru.
Metoda onSubmit se volá jen v případě, že je formulář
skutečně odeslán, není potřeba znovu kontrolovat přes
isSubmitted. Maximálně pokud můžeme zjistit, jakým prvkem byl
formulář odeslán. onSubmit se provede pouze pokud byl formulář
úspěšně a validně odeslán.
Obslužné handlery musíme nějak výstižně pojmenovávat, nesmí se nám
zaměňovat název s metodou handle{Signal}. Takovou klasikou bývá
{componentName}{event-occured}, tedy třeba
loginFormSubmitted. To ale záleží na uvážení programátora.
Tato metoda také pobírá jeden argument, kterým je instance formuláře.
Nikdy neregistrujte AppForm ve fázi render! Na
registraci v této fázi je již příliš pozdě (AppForm
nemůže přijímat signály), proto používejte k registraci komponent továrničky
(viz příklad). Komponenty se vám tak vytvoří automaticky, vždy když budou
potřeba (už nikdy ne pozdě).
Obsluha událostí
Pro obsluhu událostí se doporučuje používat následující vzor (viz Best practice: Formulářová tlačítka):
class SomePresenter extends BasePresenter
{
// obslužné handlery:
public function okClicked(SubmitButton $button)
{
// submitted and valid
Debug::dump($button->getForm()->getValues());
$this->redirect(...);
}
public function cancelClicked(SubmitButton $button)
{
// process cancelled
$this->redirect(...);
}
public function formSubmitted(AppForm $form)
{
// manual processing
if (!$form['cancel']->isSubmittedBy()) { ... }
}
protected function createComponentMyForm($name)
{
$form = new AppForm($this, $name);
$form->addText('name', 'Your name:');
$form->addSubmit('ok', 'Send')
->onClick[] = array($this, 'okClicked');
$form->addSubmit('cancel', 'Cancel')
->setValidationScope(FALSE) // prvek se nebude validovat
->onClick[] = array($this, 'cancelClicked');
// alternativa:
// $form->onSubmit[] = array($this, 'formSubmitted');
}
}
Obslužný handler pro onSubmit lze použít v případě, kdy
formulář nemá žádné nebo právě jedno tlačítko. V odstatních
situacích bývá vhodnější využít handler onClick přímo na
tlačítku.
Handler onClick se volá před handlerem onSubmit.
Handlery se volají pouze v případě, že je odeslání validní.
Uvnitř metody OkClicked tedy není nutné ověřovat validitu
formuláře. Naopak metoda FormSubmitted může být zavolána i v případě
nevalidního formuláře, byl-li odeslán tlačítkem Cancel.
V případě, že formulář nebyl odeslán tlačítkem (například byl
odeslán přes JavaScript), nebo se tak tváří kvůli chybě v Internet
Exploreru, bude Nette za odesílací tlačítko považovat první tlačítko
formuláře. Tudíž obsluha přes události onClick je
spolehlivá.
Kontrola odeslání formuláře
Použití kontroly odeslání formuláře by mohlo vypadat takto:
if ($form->isSubmitted()) { ... }
Přídklad by nám vrátil objekt implementující rozhraní
ISubmitterControl (nejčastěji objekt SubmitButton)
v případě, že je formulář odeslán nebo FALSE jestliže
není. Nevadí, že vrácená hodnota je objekt, podmínka se vyhodnotí
korektně.
Můžeme se dotázat, přímo byl formulář odeslán přes konkrétní tlačítko:
if ($form['preview']->isSubmittedBy()) { ... }
Tímto způsobem je i možné postihnout případné složitější struktury:
if ($form['subform']['preview']->isSubmittedBy()) { ... }
Validace jednotlivých prvků formuláře
U každého tlačítka je možné nastavit, jestli vyžaduje validaci:
$form->addSubmit('cancel', 'Cancel')
->setValidationScope(FALSE); // nebude se nic validovat
Funkce se jmenuje tak proto, že se plánuje její rozšíření o možnost předat pole nebo skupinu (to zůstává k diskusi) prvků, na které se validace při stisku tlačítka omezí.
Vynechání prvku z vykreslování
$form['save']->setRendered(TRUE);
Tímto zavoláním vynecháme prvek z vykreslování. Formulář ho pak považuje za vykreslený, tudíž ho nevykreslí, a my si jej pak můžeme vykreslit v šabloně ručně. To se hodí v případech, kdy chceme například vykreslit samostatně více odesílacích tlačítek vedle sebe.
Příklad více formulářů na jedné stránce
class SomePresenter extends BasePresenter
{
public function formASubmitted(AppForm $form)
{
// zpracování formA
Debug::dump($form->getValues());
}
public function formBSubmitted(AppForm $form)
{
// zpracování formB
Debug::dump($form->getValues());
}
protected function createComponentFormA($name)
{
$form = new AppForm($this, $name);
// ... definice formuláře A
$form->onSubmit[] = array($this, 'formASubmitted');
}
protected function createComponentFormB($name)
{
$form = new AppForm($this, $name);
// ... definice formuláře B
$form->onSubmit[] = array($this, 'formBSubmitted');
}
}
}
Defaultně action formuláře ukazuje na stejný view/action se stejnými
parametry, jen se do URL přidá signál (?do=formA-submit), který
Nette předá příslušnému formuláři a ten se podle toho zařídí (zavolá
si metody definované v onSubmit). Pokud se má formulář
odesílat do jiného view, tak je potřeba ten signál přidat do
argumentů.
Iterování nad formulářem
K iterování nad formulářem stejně jako nad polem svádí zápisy
$form['name']->... tedy:
foreach ($form as $name => $component) { ... }
což je samozřejmě možné, ale zvažme, že ne každá komponenta
$form je prvek FormControl. Můžou tam být
jakékoliv jiné komponenty, nebo kontainery, které teprve obsahují prvky
formuláře, případně další kontainery atd. Pro iterování je lepší
použít šikovnou metodu $form->getComponents($deep = FALSE, $type =
NULL), kde první parametr říká, zda se má iterovat do hloubky (tj.
projít i prvky konteinerů) a druhý nastavuje volitelný filtr:
foreach ($form->getComponents(TRUE, 'Nette\Forms\IFormControl') as $control) {
$control->setValue(...);
}
Viz také:
- Best practice: Formulářová tlačítka
- Vlastní vykreslování formulářů
- Formuláře, podmínky a pravidla
- Zprávy z modelu do formuláře
- Nette\Application\AppForm API reference



