Nette Documentation Preview

syntax
Multiplier: Динамические компоненты
***********************************

Инструмент для динамического создания интерактивных компонентов.

Давайте начнем с типичной проблемы: у нас есть список товаров на сайте электронной коммерции, и мы хотим сопроводить каждый товар формой *добавить в корзину*. Один из способов — обернуть весь листинг в одну форму. Более удобным способом является использование [api:Nette\Application\UI\Multiplier].

Multiplier позволяет определить фабрику для нескольких компонентов. Он основан на принципе вложенных компонентов — каждый компонент, наследующий от [api:Nette\ComponentModel\Container], может содержать другие компоненты.

См. [модель компонента|components#Components in Depth] в документации.

Multiplier представляет собой родительский компонент, который может динамически создавать свои дочерние компоненты, используя обратный вызов, переданный в конструкторе. См. пример:

```php
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;
	});
}
```

В шаблоне мы можем отобразить форму для каждого товара — и каждая форма действительно будет уникальным компонентом.

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

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

Аргумент, переданный в тег `{control}`, гласит:

1. получить компонент `shopForm`
2. вернуть своему потомку `$item->id`

При первом вызове **1.** компонент `shopForm` ещё не существует, поэтому для его создания вызывается метод `createComponentShopForm`. Затем вызывается анонимная функция, переданная в качестве параметра в Multiplier, и создается форма.

В последующих итерациях `foreach` метод `createComponentShopForm` больше не вызывается, поскольку компонент уже существует. Но поскольку мы ссылаемся на другого потомка (`$item->id` варьируется между итерациями), анонимная функция вызывается снова и создается новая форма.

Последнее, что нужно сделать, это убедиться, что форма действительно добавляет правильный товар в корзину, потому что в текущем состоянии все формы равны, и мы не можем различить, к каким продуктам они принадлежат. Для этого мы можем использовать свойство класса Multiplier (и вообще любого метода фабрики компонентов в фреймворке Nette), что каждый метод фабрики компонентов получает имя созданного компонента в качестве первого аргумента. В нашем случае это будет `$item->id`, что именно то, что нам нужно, чтобы различать отдельные товары. Всё, что вам нужно сделать, это изменить код для создания формы:

```php
protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function ($itemId) {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('amount', 'Количество:')
			->setRequired();
		$form->addHidden('itemId', $itemId);
		$form->addSubmit('send', 'Добавить в корзину');
		return $form;
	});
}
```

Multiplier: Динамические компоненты

Инструмент для динамического создания интерактивных компонентов.

Давайте начнем с типичной проблемы: у нас есть список товаров на сайте электронной коммерции, и мы хотим сопроводить каждый товар формой добавить в корзину. Один из способов — обернуть весь листинг в одну форму. Более удобным способом является использование Nette\Application\UI\Multiplier.

Multiplier позволяет определить фабрику для нескольких компонентов. Он основан на принципе вложенных компонентов — каждый компонент, наследующий от Nette\ComponentModel\Container, может содержать другие компоненты.

См. модель компонента в документации.

Multiplier представляет собой родительский компонент, который может динамически создавать свои дочерние компоненты, используя обратный вызов, переданный в конструкторе. См. пример:

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;
	});
}

В шаблоне мы можем отобразить форму для каждого товара — и каждая форма действительно будет уникальным компонентом.

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

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

Аргумент, переданный в тег {control}, гласит:

  1. получить компонент shopForm
  2. вернуть своему потомку $item->id

При первом вызове 1. компонент shopForm ещё не существует, поэтому для его создания вызывается метод createComponentShopForm. Затем вызывается анонимная функция, переданная в качестве параметра в Multiplier, и создается форма.

В последующих итерациях foreach метод createComponentShopForm больше не вызывается, поскольку компонент уже существует. Но поскольку мы ссылаемся на другого потомка ($item->id варьируется между итерациями), анонимная функция вызывается снова и создается новая форма.

Последнее, что нужно сделать, это убедиться, что форма действительно добавляет правильный товар в корзину, потому что в текущем состоянии все формы равны, и мы не можем различить, к каким продуктам они принадлежат. Для этого мы можем использовать свойство класса Multiplier (и вообще любого метода фабрики компонентов в фреймворке Nette), что каждый метод фабрики компонентов получает имя созданного компонента в качестве первого аргумента. В нашем случае это будет $item->id, что именно то, что нам нужно, чтобы различать отдельные товары. Всё, что вам нужно сделать, это изменить код для создания формы:

protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function ($itemId) {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('amount', 'Количество:')
			->setRequired();
		$form->addHidden('itemId', $itemId);
		$form->addSubmit('send', 'Добавить в корзину');
		return $form;
	});
}