Replikátor
formulářových kontejnerů $form->addDynamic()
Jednoduchý formulářový kontejner, který umožňuje zpracování dynamického počtu elementů.
| Download | Kdyby/Framework – Replicator |
|---|---|
| Sandbox | hosiplan/nette-adddynamic |
Instalace
Soubor umístíme do složky, kde jej najde RobotLoader a do
app/boostrap.php, nebo do BasePresenter::startup()
zkopírujte následující řádek
Kdyby\Forms\Containers\Replicator::register();
Připojení do formuláře
Jde používat na jednoduché věci, jako je třeba seznam datumů
use Nette\Forms\Container;
$form->addDynamic('dates', function (Container $container) {
$container->addDate('date');
});
Nebo na složité kombinace, třeba uživatelů a jejich adres
$form->addDynamic('users', function (Container $user) {
$user->addText('name', 'Jméno');
$user->addText('surname', 'Příjmení');
$user->addDynamic('addresses', function (Container $address) {
$address->addText('street', 'Ulice');
$address->addText('city', 'Město');
$address->addText('zip', 'PSČ');
// ...
}, 1);
// ...
}, 2);
Zpracování
Zpracování je triviální, stačí projít hodnoty od uživatele, třeba v cyklu.
use Nette\Application\UI\Form;
public function FormSubmitted(Form $form)
{
foreach ($form['users']->values as $user) { // hodnoty formulářového prvku
dump($user['name'] . ' ' . $user['surname']);
foreach ($user['addresses'] as $address) { // pracujeme s polem hodnot
dump($address['city']);
}
}
}
Replicator se krajně nehodí na zpracovávání uploadů. Pokud nemáte detailní znalosti fungování formulářů a vyloženě nepotřebujete funkčnost Replicatoru, zvažte raději použití nějaké „Multiple File Upload“ komponenty.
Editace záznamů
Vhodné je používat klíče jednotlivých vnořených kontejnerů jako identifikátory. Z povahy formulářových kontejnerů je pak možný třeba i tento zápis
public function actionEditUsers()
{
$form = $this['myForm'];
if (!$form->isSubmitted()) { # pokud nebyl formulář odeslán
# předpokládá model ve vlastnosti $model presenteru
$users = $this->model->findAll();
foreach ($users as $user) {
$form['users'][$user->id]->setValues($user);
# naplní kontejner výchozími hodnotami
}
}
}
A upravím zpracování
public function FormSubmitted(Form $form)
{
foreach ($form['users']->values as $userId => $user) {
# nyní mám přístupné ID uživatele i hodnoty z formuláře
// ...
Přidávání a odebírání kontejnerů
V sandboxu je příklad, kde je na řádku kontejneru tlačítko smazat a pod všemi kontejnery je tlačítko přidat.
protected function createComponentMyForm()
{
$form = new Nette\Application\UI\Form;
// jméno, továrnička, výchozí počet
$removeEvent = callback($this, 'MyFormRemoveElementClicked');
$users = $form->addDynamic('users', function (Container $user) use ($removeEvent) {
// ...
$user->addSubmit('remove', 'Smazat')
->setValidationScope(FALSE) # zakáže validaci
->onClick[] = $removeEvent;
}, 1);
$users->addSubmit('add', 'Přidat dalšího člověka')
->setValidationScope(FALSE)
->onClick[] = callback($this, 'MyFormAddElementClicked');
// ...
Zpracování přidání tlačítka je jednoduché. Tento příklad se hodí, pokud je uživatel zvyklý si políčka „naklikat“ a pak je vyplnit najednou a odeslat.
use Nette\Forms\Controls\SubmitButton;
public function MyFormAddElementClicked(SubmitButton $button)
{
$button->parent->createOne();
}
Pokud chcete dovolit vždy přidat pouze jedno další prázdné políčko, pak můžete ověřovat, jestli jsou ta současná už vyplněná a podmínit přidání.
public function MyFormAddElementClicked(SubmitButton $button)
{
$users = $button->parent;
// spočítat, jestli byly vyplněny políčka
// ignorovat hodnotu tlačítka
if ($users->isAllFilled()) {
// přidá jeden řádek do containeru
$button->parent->createOne();
}
}
Methoda Replicator::isAllFilled() kontroluje, jestli prvky
formuláře obsahují nějaké hodnoty a její argument říká, které nemá
kontrolovat.
Když uživatel klikne na smazat, provede se následující událost
public function MyFormRemoveElementClicked(SubmitButton $button)
{
// první parent je kontejner
// druhý parent je jeho replikátor
$users = $button->parent->parent;
$users->remove($button->parent, TRUE);
}
Pokud bych chtěl například smazat uživatele i z databáze a mám klíče prvků jako identifikátory, pak získám hodnotu takto:
public function MyFormRemoveElementClicked(SubmitButton $button)
{
$id = $button->parent->name;
Vlastní vykreslování
Protože je možné, že do replikátoru přidáte i tlačítko, existuje
zde metoda getContainers(), která nám vrátí pouze kontejnery.
{form myForm}
{foreach $form['users']->containers as $user}
{$user['name']->control} {$user['name']->label}
{/foreach}
{/form}
Nebo s použitím formulářových maker
{form myForm}
{foreach $form['users']->containers as $id => $user}
{input users-$id-name} {label users-$id-name /}
{/foreach}
{/form}
