Multiplier: componenti dinamici
Uno strumento per creare dinamicamente componenti interattivi.
Cominciamo con un esempio tipico: immaginate l'elenco dei prodotti di un e-shop, in cui per ogni articolo volete un form “Aggiungi al carrello”. Un approccio possibile è racchiudere l'intero elenco in un unico form. Un metodo molto più comodo lo offre però Nette\Application\UI\Multiplier.
Multiplier vi permette di definire comodamente una factory per più componenti. Funziona sul principio dei componenti annidati: qualsiasi componente che eredita da Nette\ComponentModel\Container può contenere altri componenti.
Vedi nella documentazione il capitolo sul modello a componenti.
L'essenza di Multiplier sta nel fatto che agisce da genitore capace di creare dinamicamente i propri figli tramite una callback passata al costruttore. Ecco l'esempio:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function () {
$form = new Nette\Application\UI\Form;
$form->addInteger('amount', 'Quantità:')
->setRequired();
$form->addSubmit('send', 'Aggiungi al carrello');
return $form;
});
}
Ora, nel template, possiamo semplicemente disegnare il form per ogni prodotto, e ognuno sarà davvero un componente a sé.
{foreach $items as $item}
<h2>{$item->title}</h2>
{$item->description}
{control "shopForm-$item->id"}
{/foreach}
L'argomento passato nel tag {control} segue un formato che significa:
- Ottieni il componente
shopForm. - Da esso ottieni il figlio chiamato
$item->id.
Alla prima esecuzione del punto 1 il componente shopForm non esiste ancora, quindi viene chiamata la sua
factory createComponentShopForm. Poi, sul componente ottenuto (un'istanza di Multiplier), viene chiamata la factory
del form specifico, cioè la funzione anonima che abbiamo passato al costruttore di Multiplier.
Nell'iterazione successiva del ciclo foreach il metodo createComponentShopForm non verrà chiamato di nuovo
(perché il componente esiste già). Poiché però cerchiamo un figlio diverso (dato che $item->id sarà diverso a
ogni iterazione), la funzione anonima verrà chiamata di nuovo e restituirà un nuovo form.
Resta solo da garantire che il form aggiunga al carrello il prodotto giusto: al momento il form è identico per ogni prodotto.
Qui ci aiuta una caratteristica di Multiplier (e in generale di qualsiasi factory di componenti in Nette Framework): ogni factory
riceve come primo argomento il nome del componente che si sta creando. La factory di Multiplier riceve inoltre come secondo
argomento l'istanza stessa di Multiplier. Nel nostro caso il primo argomento sarà $item->id, che è esattamente
l'informazione che ci serve. Basta quindi modificare leggermente la creazione del form:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function (string $itemId) {
$form = new Nette\Application\UI\Form;
$form->addInteger('amount', 'Quantità:')
->setRequired();
$form->addHidden('itemId', $itemId);
$form->addSubmit('send', 'Aggiungi al carrello');
return $form;
});
}