Nette Documentation Preview

syntax
Multiplier: componentes dinâmicos
*********************************

.[perex]
Ferramenta para criação dinâmica de componentes interativos

Vamos partir de um exemplo típico: temos uma lista de produtos em uma loja virtual, e para cada um queremos exibir um formulário para adicionar o produto ao carrinho. Uma das opções possíveis é envolver toda a listagem em um único formulário. No entanto, um método muito mais conveniente nos é oferecido pelo [api:Nette\Application\UI\Multiplier].

O Multiplier permite definir convenientemente uma pequena fábrica para múltiplos componentes. Funciona com base no princípio de componentes aninhados - cada componente que herda de [api:Nette\ComponentModel\Container] pode conter outros componentes.

.[tip]
Veja o capítulo sobre o [modelo de componentes |components#Componentes em profundidade] na documentação ou a [palestra de Honza Tvrdík|https://www.youtube.com/watch?v=8y3LLexWu-I].

A essência do Multiplier é que ele atua na posição de pai, que pode criar seus descendentes dinamicamente usando um callback passado no construtor. Veja o exemplo:

```php
protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function () {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('count', 'Quantidade de produtos:')
			->setRequired();
		$form->addSubmit('send', 'Adicionar ao carrinho');
		return $form;
	});
}
```

Agora podemos, no template, simplesmente deixar renderizar o formulário para cada produto - e cada um será realmente um componente único.

```latte
{foreach $items as $item}
	<h2>{$item->title}</h2>
	{$item->description}

	{control "shopForm-$item->id"}
{/foreach}
```

O argumento passado na tag `{control}` está em um formato que diz:

1. obtenha o componente `shopForm`
2. e dele obtenha o descendente `$item->id`

Na primeira chamada do ponto **1.**, `shopForm` ainda não existe, então sua fábrica `createComponentShopForm` é chamada. No componente obtido (instância do Multiplier), a fábrica do formulário específico é então chamada - que é a função anônima que passamos para o Multiplier no construtor.

Na próxima iteração do foreach, o método `createComponentShopForm` não será mais chamado (o componente existe), mas como estamos procurando por um descendente diferente dele (`$item->id` será diferente em cada iteração), a função anônima será chamada novamente e nos retornará um novo formulário.

A única coisa que resta é garantir que o formulário adicione ao carrinho realmente o produto que deve - atualmente, o formulário é completamente idêntico para cada produto. A propriedade do Multiplier (e geralmente de cada fábrica de componentes no Nette Framework) nos ajudará, que é que cada fábrica recebe como seu primeiro argumento o nome do componente sendo criado. No nosso caso, será `$item->id`, que é exatamente a informação que precisamos. Basta, portanto, ajustar ligeiramente a criação do formulário:

```php
protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function ($itemId) {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('count', 'Quantidade de produtos:')
			->setRequired();
		$form->addHidden('itemId', $itemId);
		$form->addSubmit('send', 'Adicionar ao carrinho');
		return $form;
	});
}
```

Multiplier: componentes dinâmicos

Ferramenta para criação dinâmica de componentes interativos

Vamos partir de um exemplo típico: temos uma lista de produtos em uma loja virtual, e para cada um queremos exibir um formulário para adicionar o produto ao carrinho. Uma das opções possíveis é envolver toda a listagem em um único formulário. No entanto, um método muito mais conveniente nos é oferecido pelo Nette\Application\UI\Multiplier.

O Multiplier permite definir convenientemente uma pequena fábrica para múltiplos componentes. Funciona com base no princípio de componentes aninhados – cada componente que herda de Nette\ComponentModel\Container pode conter outros componentes.

Veja o capítulo sobre o modelo de componentes na documentação ou a palestra de Honza Tvrdík.

A essência do Multiplier é que ele atua na posição de pai, que pode criar seus descendentes dinamicamente usando um callback passado no construtor. Veja o exemplo:

protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function () {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('count', 'Quantidade de produtos:')
			->setRequired();
		$form->addSubmit('send', 'Adicionar ao carrinho');
		return $form;
	});
}

Agora podemos, no template, simplesmente deixar renderizar o formulário para cada produto – e cada um será realmente um componente único.

{foreach $items as $item}
	<h2>{$item->title}</h2>
	{$item->description}

	{control "shopForm-$item->id"}
{/foreach}

O argumento passado na tag {control} está em um formato que diz:

  1. obtenha o componente shopForm
  2. e dele obtenha o descendente $item->id

Na primeira chamada do ponto 1., shopForm ainda não existe, então sua fábrica createComponentShopForm é chamada. No componente obtido (instância do Multiplier), a fábrica do formulário específico é então chamada – que é a função anônima que passamos para o Multiplier no construtor.

Na próxima iteração do foreach, o método createComponentShopForm não será mais chamado (o componente existe), mas como estamos procurando por um descendente diferente dele ($item->id será diferente em cada iteração), a função anônima será chamada novamente e nos retornará um novo formulário.

A única coisa que resta é garantir que o formulário adicione ao carrinho realmente o produto que deve – atualmente, o formulário é completamente idêntico para cada produto. A propriedade do Multiplier (e geralmente de cada fábrica de componentes no Nette Framework) nos ajudará, que é que cada fábrica recebe como seu primeiro argumento o nome do componente sendo criado. No nosso caso, será $item->id, que é exatamente a informação que precisamos. Basta, portanto, ajustar ligeiramente a criação do formulário:

protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function ($itemId) {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('count', 'Quantidade de produtos:')
			->setRequired();
		$form->addHidden('itemId', $itemId);
		$form->addSubmit('send', 'Adicionar ao carrinho');
		return $form;
	});
}