Moltiplicatore: Componenti dinamici
Uno strumento per la creazione dinamica di componenti interattivi
Cominciamo con un problema tipico: abbiamo un elenco di prodotti su un sito di e-commerce e vogliamo accompagnare ogni prodotto con un modulo aggiungi al carrello. Un modo è quello di racchiudere l'intero elenco in un unico modulo. Un modo più comodo è usare Nette\Application\UI\Multiplier.
Multiplier consente di definire un factory per più componenti. Si basa sul principio dei componenti annidati: ogni componente che eredita da Nette\ComponentModel\Container può contenere altri componenti.
Vedere il modello dei componenti nella documentazione.
Multiplier si pone come un componente genitore che può creare dinamicamente i suoi figli, utilizzando il callback passato nel costruttore. Si veda l'esempio:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function () {
$form = new Nette\Application\UI\Form;
$form->addInteger('amount', 'Amount:')
->setRequired();
$form->addSubmit('send', 'Add to cart');
return $form;
});
}
Nel modello possiamo rendere un modulo per ogni prodotto e ogni modulo sarà effettivamente un componente unico.
{foreach $items as $item}
<h2>{$item->title}</h2>
{$item->description}
{control "shopForm-$item->id"}
{/foreach}
L'argomento passato al tag {control}
dice:
- ottenere un componente
shopForm
- e restituire il suo figlio
$item->id
Durante la prima chiamata di 1. il componente shopForm
non esiste ancora, quindi viene chiamato il metodo
createComponentShopForm
per crearlo. Viene quindi richiamata una funzione anonima passata come parametro a Multiplier
e viene creato un modulo.
Nelle iterazioni successive di foreach
il metodo createComponentShopForm
non viene più chiamato,
perché il componente esiste già. Ma poiché si fa riferimento a un altro figlio ($item->id
varia tra le
iterazioni), viene chiamata nuovamente una funzione anonima e viene creato un nuovo modulo.
L'ultima cosa da fare è assicurarsi che il form aggiunga effettivamente il prodotto corretto al carrello, perché nello stato
attuale tutti i form sono uguali e non possiamo distinguere a quali prodotti appartengono. Per questo possiamo usare la
proprietà di Multiplier (e in generale di ogni metodo di fabbrica di componenti in Nette Framework), secondo cui ogni metodo di
fabbrica di componenti riceve come primo parametro il nome del componente creato. Nel nostro caso si tratta di
$item->id
, che è esattamente ciò di cui abbiamo bisogno per distinguere i singoli prodotti. È sufficiente
modificare il codice per la creazione del modulo:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function ($itemId) {
$form = new Nette\Application\UI\Form;
$form->addInteger('amount', 'Amount:')
->setRequired();
$form->addHidden('itemId', $itemId);
$form->addSubmit('send', 'Add to cart');
return $form;
});
}