Multiplicador: Componentes dinâmicos
Uma ferramenta para a criação dinâmica de componentes interativos
Vamos começar com um problema típico: temos uma lista de produtos em um site de comércio eletrônico e queremos acompanhar cada produto com um formulário add to cart. Uma das maneiras é envolver toda a lista em um único formulário. Uma maneira mais conveniente é usar Nette\Application\UI\Multiplier.
O multiplicador permite definir uma fábrica para múltiplos componentes. Ele se baseia no princípio de componentes aninhados – cada componente herdado de Nette\ComponentModel\Container pode conter outros componentes.
Veja o modelo dos componentes na documentação.
O multiplicador posa como um componente pai que pode criar dinamicamente seus filhos usando a callback passada no construtor. Veja o exemplo:
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;
});
}
No modelo podemos apresentar um formulário para cada produto – e cada formulário será de fato um componente único.
{foreach $items as $item}
<h2>{$item->title}</h2>
{$item->description}
{control "shopForm-$item->id"}
{/foreach}
Argumento passado para {control}
tag diz:
- obter um componente
shopForm
- e devolver seu filho
$item->id
Durante a primeira chamada de 1. o componente shopForm
ainda não existe, portanto o método
createComponentShopForm
é chamado para criá-lo. Uma função anônima passada como parâmetro para
o Multiplicador, é então chamada e um formulário é criado.
Nas iterações subsequentes do foreach
o método createComponentShopForm
não é mais chamado
porque o componente já existe. Mas como fazemos referência a outra criança ($item->id
varia entre
iterações), uma função anônima é chamada novamente e uma nova forma é criada.
A última coisa é garantir que o formulário realmente acrescente o produto correto ao carrinho porque no estado atual
todos os formulários são iguais e não podemos distinguir a que produtos eles pertencem. Para isso, podemos usar a propriedade
de Multiplicador (e em geral de qualquer método de fábrica de componentes em Nette Framework) que cada método de fábrica de
componentes recebe o nome do componente criado como o primeiro argumento. Em nosso caso, isso seria $item->id
,
que é exatamente o que precisamos para distinguir os produtos individuais. Tudo o que precisamos fazer é modificar o código
para criar o formulário:
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;
});
}