Multiplier: dynamiczne komponenty
Narzędzie do dynamicznego tworzenia komponentów interaktywnych.
Zacznijmy od typowego przykładu: wyobraź sobie listę produktów w sklepie internetowym, przy której chcesz wyświetlić dla każdego artykułu formularz “Do koszyka”. Jedną z możliwości jest opakowanie całej listy w jeden formularz. O wiele wygodniejszy sposób oferuje jednak Nette\Application\UI\Multiplier.
Multiplier pozwala wygodnie zdefiniować fabrykę dla wielu komponentów. Działa na zasadzie komponentów zagnieżdżonych – każdy komponent dziedziczący po Nette\ComponentModel\Container może zawierać inne komponenty.
Zobacz w dokumentacji rozdział o modelu komponentów.
Istota Multipliera polega na tym, że działa jak rodzic, który potrafi dynamicznie tworzyć swoich potomków za pomocą callbacku przekazanego w konstruktorze. Zobacz przykład:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function () {
$form = new Nette\Application\UI\Form;
$form->addInteger('amount', 'Ilość:')
->setRequired();
$form->addSubmit('send', 'Do koszyka');
return $form;
});
}
Teraz w szablonie możemy po prostu wyrenderować formularz dla każdego produktu – i każdy naprawdę będzie osobnym komponentem.
{foreach $items as $item}
<h2>{$item->title}</h2>
{$item->description}
{control "shopForm-$item->id"}
{/foreach}
Argument przekazany w tagu {control} ma format, który oznacza:
- Pobierz komponent
shopForm. - Z niego pobierz potomka o nazwie
$item->id.
Przy pierwszym wywołaniu punktu 1 komponent shopForm jeszcze nie istnieje, więc wywoływana jest jego
fabryka createComponentShopForm. Następnie na uzyskanym komponencie (instancji Multipliera) wywoływana jest fabryka
konkretnego formularza, czyli anonimowa funkcja, którą przekazaliśmy do konstruktora Multipliera.
W kolejnej iteracji pętli foreach metoda createComponentShopForm nie zostanie wywołana ponownie (bo komponent
już istnieje). Ponieważ jednak szukamy innego potomka ($item->id będzie w każdej iteracji inne), anonimowa
funkcja zostanie wywołana ponownie i zwróci nowy formularz.
Pozostaje już tylko zadbać o to, aby formularz dodawał do koszyka właściwy produkt – obecnie formularz jest identyczny
dla każdego produktu. Pomaga nam w tym cecha Multipliera (i ogólnie każdej fabryki komponentów w Nette Framework): każda
fabryka otrzymuje jako pierwszy argument nazwę tworzonego komponentu. Ponadto fabryka Multipliera otrzymuje jako drugi argument
samą instancję Multipliera. W naszym przypadku pierwszym argumentem będzie $item->id, czyli dokładnie ta
informacja, której potrzebujemy. Wystarczy więc nieznacznie zmodyfikować tworzenie formularza:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function (string $itemId) {
$form = new Nette\Application\UI\Form;
$form->addInteger('amount', 'Ilość:')
->setRequired();
$form->addHidden('itemId', $itemId);
$form->addSubmit('send', 'Do koszyka');
return $form;
});
}