Kde plnit formulář defaultními hodnotami?
- duke
- Člen | 650
Kde je dle vašeho názoru nejlepší volat metodu setDefaults()
?
Zdá se, že většina lidí to řeší přímo v továrničce, což ale
znamená, že v případě zpracování formuláře se v některých
případech (pokud tyto hodnoty nejsou použity ještě k jiným účelům)
zbytečně ztrácí čas načítáním těchto hodnot (např z databáze),
neboť v tomto případě je metoda setDefaults()
stejně
zahodí.
V té souvislosti mě napadlo, zda by nebylo dobré přidat formulářům callback pro načtení defaultních hodnot, který by se automaticky volal, až by to bylo třeba. Tj. před vyrenderováním a jen za předpokladu, že neprobíhá zpracování formuláře.
- hAssassin
- Člen | 293
Osobne se prikladnim to plnit v tovarnicce nebo v action. Action se provadi po odeslani stejne pred volanim callbacku, ale je fakt ze to nebude lazy.
A proc v tovarnicce? Ty data, at jsou jakkoliv slozita, jsou potreba vzdy, ikdyz budou hnedle prepsany. Co kdyby ti nekdo podstrcil neplatnou hodnotu selektu? Potom tam musis nastavit tu vychozi. Ale kde ji vezmes, pokud tam ty vychozi hodnoty nebudes nastavovat?
Jinak napad s tim callbackem neni spatny, ale pokud dava smysl to co jsem napsal vys (a me to smysl dava), pak je zbytecny… Co ty na to?
- duke
- Člen | 650
Tak jsem si ujasnil, že toto není obecně vyřešený problém, a každý si to řeší po svém. Krom strohé odpovědi, kde to voláte, jsem očekával také i nějaké argumenty, proč tak a ne jinak, a vyjádření k nápadu ohledně callbacku. V tomto směru děkuji především hAssassinovi. Doufám, že přibudou i další reakce.
Jinak bych ještě doplnil původní otázku o pod-otázku, kde voláte
setDefaults
u formulářů, jež nejsou přímo v presenteru, ale
hlouběji v hierarchii komponent.
hAssassin napsal:
Osobne se prikladnim to plnit v tovarnicce nebo v action. Action se provadi po odeslani stejne pred volanim callbacku, ale je fakt ze to nebude lazy.
Přesně tak. Pokud to bude v action nebo render metodě, nebude to lazy, což je škoda.
hAssassin napsal:
A proc v tovarnicce? Ta data, at jsou jakkoliv slozita, jsou potreba vzdy, i kdyz budou hnedle prepsana.
Někdy jsou opravdu ona data potřeba. Např. když chceme detekovat, že od posledního zobrazení někdo data pozměnil z vnějšku, a zabránit tak ztrátě dat, ale i v jiných případech. Nemyslím si ale, že z toho vyplývá, že je třeba načítat všechny hodnoty znovu vždy, jak tvrdíš. Nejde vždy jen o editaci nějakého záznamu, může jít i o jeho vytvoření, přičemž se do defaultních hodnot mohou předvyplnit data daná složitým výpočtem a je zbytečné tento výpočet opakovat při každém submitu formuláře (včetně submitů s chybami mimochodem), když bude jeho výsledek zahozen…
hAssassin napsal:
Co kdyby ti nekdo podstrcil neplatnou hodnotu selektu? Potom tam musis nastavit tu vychozi. Ale kde ji vezmes, pokud tam ty vychozi hodnoty nebudes nastavovat?
Dřív se toto dalo řešit validačním pravidlem, které v takovém
případě označilo select jako nevalidní a callback onSuccess
se
v takovém případě tedy nezavolal. Nedávno bylo toto validační pravidlo
přidáno do selektů automaticky, viz tento commit.
hAssassin napsal:
Jinak napad s tim callbackem neni spatny, ale pokud dava smysl to co jsem napsal vys (a me to smysl dava), pak je zbytecny… Co ty na to?
IMHO není zbytečný, protože umožňuje naprosto lazy řešení (tj. více
lazy, než řešení skrz továrničku, neboť továrnička se může volat,
i když se formulář nakonec vůbec nevykreslí).
Ale možná jsem přehlédl něco, co stojí řešení callbackem v cestě, a
proto se Vás také ptám, co vy na to…
Editoval duke (17. 4. 2013 18:48)
- Jan Tvrdík
- Nette guru | 2595
Přesně tak. Pokud to bude v action nebo render metodě, nebude to lazy, což je škoda.
V render*
metodě to bude v podstatě lazy (nastaví se to při
vykreslení, ale už ne při zpracování, kdy to není většinou
potřeba).
Důvod, proč to radši dělám v render*
metodě je, že
ušetřím pár znaků. Srovnej následující dvě řešení.
public function renderEdit($id)
{
$article = $this->model->load($id);
if (!$article) $this->error();
$this['editForm']->setDefaults($article);
}
protected function createComponentEditForm()
{
$form = new UI\Form();
...
return $form;
}
private $article;
public function actionEdit($id)
{
$this->article = $this->model->load($id);
if (!$this->article) $this->error();
}
protected function createComponentEditForm()
{
$form = new UI\Form();
...
$form->setDefaults($this->article);
return $form;
}
- duke
- Člen | 650
David Grudl napsal:
Co může být více lazy než továrnička? Nevidím důvod ji nevyužít.
Více lazy je právě to řešení přes callback, který se volá, až když je to nezbytně nutné. Tj. např. callback navázaný na událost onBeforeRender. Již jsem to zdůvodnil ve svém prvním příspěvku. Jde o to, že plnit formulář daty je třeba pouze v případě, kdy formulář není odeslán. Plnit ho, i když probíhá submit, je kontraproduktivní, zejména pokud je operace získání výchozích dat náročná na prostředky (např. se musí načítat z databáze).
Další důvod proč nevyužít továrničku možná zná Patrik Votoček, jak lze usuzovat z jeho doporučení. Bohužel to nezdůvodnil.
Jan Tvrdík napsal:
V render* metodě to bude v podstatě lazy (nastaví se to při vykreslení, ale už ne při zpracování, kdy to není většinou potřeba).
Zvaž případ, kdy se formulář renderuje v šabloně podmíněně (např.
podle práv uživatele editovat záznam). Pak jej voláním
$this['editForm']
zbytečně vytváříš a následně
plníš daty.
Jan Tvrdík napsal:
Důvod, proč to radši dělám v render* metodě je, že ušetřím pár znaků.
A jak to děláš u formulářů uvnitř komponent?
Editoval duke (19. 4. 2013 0:57)
- Jan Tvrdík
- Nette guru | 2595
Zvaž případ, kdy se formulář renderuje v šabloně podmíněně (např. podle práv uživatele editovat záznam). Pak jej voláním
$this['editForm']
zbytečně vytváříš a následně plníš daty.
To je strašně vzácné, nepotřebuji to nijak řešit.
A jak to děláš u formulářů uvnitř komponent?
Tam je to jedno. Asi spíš v továrničce (zase ušetřím pár znaků).
- David Grudl
- Nette Core | 8282
Takhle:
protected function createComponentEditForm($name)
{
$form = new UI\Form($this, $name);
if (!$form->isSubmitted()) {
$form->setDefaults(...);
}
return $form;
}
Jan Tvrdík napsal(a):
To je strašně vzácné, nepotřebuji to nijak řešit.
Pokud kešuješ část šablony s formulářem, tak se to hodí.
- duke
- Člen | 650
David Grudl napsal:
Takhle:
protected function createComponentEditForm($name) { $form = new UI\Form($this, $name); if (!$form->isSubmitted()) { $form->setDefaults(...); } return $form; }
Díky, toto řešení mě nenapadlo. Dodám, že v tomto případě je
možné místo setDefaults
volat přímo setValues
,
jak plyne z implementace metody setDefaults
…
Takže toto je teď oficiální best-practice pro vytváření formulářových komponent?
Ještě zde asi bude mírný nesoulad s touto featurou, kdy výše
nastíněné řešení neumožní znovunastavení disabled inputů. Takže pokud
někdo chce využívat tuto featuru, bude muset setDefaults
(alespoň s hodnotami pro disabled inputy) volat i při submitu v případě
chyby (nejlépe asi přes událost onError).
Editoval duke (23. 4. 2013 7:03)