Závislé inputy – Best practise
- nanuqcz
- Člen | 822
Ahoj,
o závislých select-boxech apod. se tu toho psalo už hodně. Žádné
řešení ale podle mě není ideální a každé způsobuje v praxi nějaké
problémy.
Příklad
Mějme jednoduchý formulář pro ukládání odkazu v menu:
class LinkForm extends Form
{
public function __construct($parent = NULL, $name = NULL)
{
parent::__construct($parent, $name);
$this->init();
}
public function init()
{
$this->addText('name', 'Název odkazu')
->setRequired('Pole %label musí být vyplněno.');
// Link type
$this->addSelect('link_type', 'Typ odkazu', array(
'article' => 'Článek',
))->setPrompt('- vyberte -');
$this->addSubmit('choose_type', 'Vybrat')
->setValidationScope(FALSE);
// Link value (depends on 'Link type')
if ($this['link_type']->value == 'article') {
$articlePairs = $this->articleService->getPairs();
$this->addSelect('link_value', 'Název článku', $articlePairs);
}
$this->addSubmit('save', 'Uložit');
}
}
Takto napsaný formulář bude fungovat. Aspoň tedy v akci pro vytváření odkazu. V editaci odkazu, kde potřebuji formulář nejdříve naplnit defaultními daty, ale fungovat nebude:
public function renderEdit($id)
{
$link = $this->linkService->get($id);
$this['linkForm']->setDefaults(array(
'name' => $link->name,
'link_type' => $link->link_type,
'link_value' => $link->link_value, // polozku 'link_value' formular v soucasne chvili nezna
));
}
Řešení
- Přetížit ve třídě
LinkForm
metodusetDefaults
a položku ‚link_value‘ k formuláři přidávat i zde.- Problém: Když v metodě
setDefaults
přidám k formuláři nějakou položku, tak ta se objeví na konci formuláře, tzn. ZA odesílacím tlačítkem. - Problém: Co když místo
$form->setDefaults
použiju$form[link_type]->setDefaultValue()
?
- Problém: Když v metodě
- Hodnoty z formuláře ukládat místo
setDefaults
dosessions
. Formulář pak na základě hodnot ze sessions přidá závislé inputy a až PAK sám na sebe zavolásetDefaults($sessions->formValues)
;- Problém: Nepřijde mi to vůbec jako hezké nebo čisté řešení.
- Problém: Co když budu mít v prohlížeči ve dvou záložkách otevřený stejný formulář, ale každý s jinými daty?
Tedy, žádné řešení není ideální a nic dalšího mě už nenapadá.
Nějaké tipy, rady, názory? Díky.
Editoval nanuqcz (3. 1. 2014 15:43)
- Robyer
- Člen | 74
Já bych to přidávání link value
oddělil do samostatné
metody, kterou bys pak mohl zavolat i přímo z presenteru. Ta by
zkontrolovala hodnotu link_type a naplnila ten select link_value správnými
daty. (Nebo by ten select úplně odstranila, pokud by link_type neměl
správnou hodnotu)
- nanuqcz
- Člen | 822
Robyer: Jak by v takovém případě vypadalo naplňování formuláře defaultními hodnotami?
// naplnim zakladni inputy
$this['linkForm']->setDefaults(array(
'name' => $link->name,
'link_type' => $link->link_type,
));
// pridam 'link_value' input
$this['linkForm']->updateLinkValueInput();
// naplnim 'link_value'
$this['linkForm']->setDefaults(array(
'link_value' => $link->link_value,
));
Takto složitý kód jen pro naplnění formuláře? Navíc, takto se ‚link_value‘ přidá na konec formuláře, až za odesilací tlačítko.
Editoval nanuqcz (3. 1. 2014 18:19)
- Robyer
- Člen | 74
Ano, nějak tak jsem to myslel. Pro tohle všechno si můžeš vytvořit třeba metodu setMyDefaults(…) ve formuláři… teď si uvědomuju, že to je vlastně podobné, jako tvé řešení #1.
Co se týče problému s přidáváním link_value na konec formuláře, tak bych ho v konstruktoru (resp. ve tvém init()) vytvářel vždy. A při zavolání updateLinkValueInput() ho pak naplnil daty nebo úplně odstranil.
Editoval Robyer (3. 1. 2014 19:00)
- David Matějka
- Moderator | 6445
premyslim a nenapada me zadny elegantni reseni. ale co takhle pridat do BaseControlu onUpdate event volany pri kazdem setValue (tedy i pri setDefaultValue)? pak by to bylo hezky
$this->addSelect('link_type', 'Typ odkazu', array(
'article' => 'Článek',
))->setPrompt('- vyberte -')->onUpdate[] = function($input) {
if ($input->value == 'article') {
$articlePairs = $this->articleService->getPairs();
$this->addSelect('link_value', 'Název článku', $articlePairs);
}
});
- nanuqcz
- Člen | 822
matej21: Kdyby se něco takového přidalo do Nette, byl bych rád.
Zároveň by se mi pak líbilo, kdyby v Nette\Forms byla možnost přesouvání prvků:
$form['link_type']->onChange[] = function($input){
// Ugly :-(
$form = $input->form;
$newSelect = new SelectBox(...);
$form->addComponent($newSelect, ..., $form['save']);
};
$form['link_type']->onChange[] = function($input){
// Nice :-)
$form = $input->form;
$form->addSelect(...)
->moveBefore($form['save']);
}
Mám sepsat Feature Request, nebo RFC?
EDIT: RFC sepsáno
Editoval nanuqcz (13. 1. 2014 2:58)
- nanuqcz
- Člen | 822
Mesiah: Skoro, musel bych je přidávat do stejné grupy
($form->addGroup(...)
) :-) To je ale jen vedlejší problém.
Hlavní problém v tomhle vlákně ale je, jak to udělat, aby se závislý
input zobrazoval jak v závislosti na odeslaných hodnotách, tak
v závislosti na nastavených hodnotách v kódu
($form->setDefaults(...)
).