Multiplier: dynamické komponenty
********************************
.[perex]
Nástroj na dynamickou tvorbu interaktivních komponent.
Vyjděme od typického příkladu: mějme seznam zboží v eshopu, přičemž u každého budeme chtít vypsat formulář pro přidání zboží do košíku. Jednou z možných variant je obalit celý výpis do jednoho formuláře. Mnohem pohodlnější způsob nám však nabízí [api:Nette\Application\UI\Multiplier].
Multiplier umožňuje pohodlně definovat továrničku pro více komponent. Funguje na principu vnořených komponent - každá komponenta dědící od [api:Nette\ComponentModel\Container] může obsahovat další komponenty.
.[tip]
Viz kapitola o [komponentovém modelu |components#Komponenty do hloubky] v dokumentaci či [přednáška od Honzy Tvrdíka|https://www.youtube.com/watch?v=8y3LLexWu-I].
Podstatou Multiplieru je, že vystupuje v pozici rodiče, který si své potomky dokáže vytvářet dynamicky pomocí callbacku předaného v konstruktoru. Viz příklad:
```php
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function () {
$form = new Nette\Application\UI\Form;
$form->addInteger('count', 'Počet zboží:')
->setRequired();
$form->addSubmit('send', 'Přidat do košíku');
return $form;
});
}
```
Nyní můžeme v šabloně jednoduše u každého zboží nechat vykreslit formulář - a každý bude skutečně unikátní komponentou.
```latte
{foreach $items as $item}
<h2>{$item->title}</h2>
{$item->description}
{control "shopForm-$item->id"}
{/foreach}
```
Argument předaný ve značce `{control}` je ve formátu, který říká:
1. získej komponentu `shopForm`
2. a z ní získej potomka `$item->id`
Při prvním volání bodu **1.** `shopForm` ještě neexistuje, takže se zavolá jeho továrna `createComponentShopForm`. Na získané komponentě (instanci Multiplieru) je pak zavolána továrna konkrétního formuláře - což je anonymní funkce, kterou jsme Multiplieru v konstruktoru předali.
V další iteraci foreache již metoda `createComponentShopForm` volána nebude (komponenta existuje), ale protože hledáme jejího jiného potomka (`$item->id` bude v každé iteraci jiné), znovu bude zavolána anonymní funkce a vrátí nám nový formulář.
Jediné, co zbývá, je zajistit, aby nám formulář do košíku přidal skutečně to zboží, které má - aktuálně je formulář u každého zboží úplně totožný. Pomůže nám vlastnost Multiplieru (a obecně každé továrny na komponentu v Nette Frameworku), a to ta, že každá továrna dostává jako svůj první argument název tvořené komponenty. Továrna Multiplieru navíc jako druhý argument dostává samotnou instanci Multiplieru. V našem případě bude prvním argumentem `$item->id`, což je přesně ten údaj, který potřebujeme. Stačí tedy lehce upravit tvorbu formuláře:
```php
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function (string $itemId) {
$form = new Nette\Application\UI\Form;
$form->addInteger('count', 'Počet zboží:')
->setRequired();
$form->addHidden('itemId', $itemId);
$form->addSubmit('send', 'Přidat do košíku');
return $form;
});
}
```
{{maintitle: Multiplier v Nette: dynamické vytváření komponent}}
{{description: Potřebujete u každého produktu formulář Přidat do košíku? Multiplier vytvoří tolik samostatných komponent, kolik je třeba, takže každá položka má tu svou.}}
Multiplier: dynamické komponenty
Nástroj na dynamickou tvorbu interaktivních komponent.
Vyjděme od typického příkladu: mějme seznam zboží v eshopu, přičemž u každého budeme chtít vypsat formulář pro
přidání zboží do košíku. Jednou z možných variant je obalit celý výpis do jednoho formuláře. Mnohem pohodlnější
způsob nám však nabízí Nette\Application\UI\Multiplier.
Multiplier umožňuje pohodlně definovat továrničku pro více komponent. Funguje na principu vnořených komponent –
každá komponenta dědící od Nette\ComponentModel\Container může
obsahovat další komponenty.
Viz kapitola o komponentovém
modelu v dokumentaci či přednáška od Honzy Tvrdíka.
Podstatou Multiplieru je, že vystupuje v pozici rodiče, který si své potomky dokáže vytvářet dynamicky pomocí
callbacku předaného v konstruktoru. Viz příklad:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function () {
$form = new Nette\Application\UI\Form;
$form->addInteger('count', 'Počet zboží:')
->setRequired();
$form->addSubmit('send', 'Přidat do košíku');
return $form;
});
}
Nyní můžeme v šabloně jednoduše u každého zboží nechat vykreslit formulář – a každý bude skutečně
unikátní komponentou.
{foreach $items as $item}
<h2>{$item->title}</h2>
{$item->description}
{control "shopForm-$item->id"}
{/foreach}
Argument předaný ve značce {control} je ve formátu, který říká:
- získej komponentu
shopForm
- a z ní získej potomka
$item->id
Při prvním volání bodu 1. shopForm ještě neexistuje, takže se zavolá jeho továrna
createComponentShopForm. Na získané komponentě (instanci Multiplieru) je pak zavolána továrna konkrétního
formuláře – což je anonymní funkce, kterou jsme Multiplieru v konstruktoru předali.
V další iteraci foreache již metoda createComponentShopForm volána nebude (komponenta existuje), ale protože
hledáme jejího jiného potomka ($item->id bude v každé iteraci jiné), znovu bude zavolána anonymní funkce
a vrátí nám nový formulář.
Jediné, co zbývá, je zajistit, aby nám formulář do košíku přidal skutečně to zboží, které má – aktuálně je
formulář u každého zboží úplně totožný. Pomůže nám vlastnost Multiplieru (a obecně každé továrny na komponentu
v Nette Frameworku), a to ta, že každá továrna dostává jako svůj první argument název tvořené komponenty. Továrna
Multiplieru navíc jako druhý argument dostává samotnou instanci Multiplieru. V našem případě bude prvním argumentem
$item->id, což je přesně ten údaj, který potřebujeme. Stačí tedy lehce upravit tvorbu formuláře:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function (string $itemId) {
$form = new Nette\Application\UI\Form;
$form->addInteger('count', 'Počet zboží:')
->setRequired();
$form->addHidden('itemId', $itemId);
$form->addSubmit('send', 'Přidat do košíku');
return $form;
});
}