Nette Documentation Preview

syntax
Multiplier: dynamiczne komponenty
*********************************

.[perex]
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 [api: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 [api:Nette\ComponentModel\Container] może zawierać inne komponenty.

.[tip]
Zobacz w dokumentacji rozdział o [modelu komponentów |components#Komponenty w głąb].

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:

```php
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.

```latte
{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:

1. Pobierz komponent `shopForm`.
2. 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:

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

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:

  1. Pobierz komponent shopForm.
  2. 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;
	});
}