Multiplier: dinamične komponente

Orodje za dinamično ustvarjanje interaktivnih komponent

Izhajajmo iz tipičnega primera: imejmo seznam blaga v spletni trgovini, pri čemer bomo pri vsakem želeli izpisati obrazec za dodajanje blaga v košarico. Ena od možnih variant je oviti celoten izpis v en obrazec. Veliko udobnejši način pa nam ponuja Nette\Application\UI\Multiplier.

Multiplier omogoča udobno definiranje tovarniške metode za več komponent. Deluje na principu ugnezdenih komponent – vsaka komponenta, ki deduje od Nette\ComponentModel\Container, lahko vsebuje druge komponente.

Glej poglavje o komponentnem modelu v dokumentaciji ali predavanje Honze Tvrdíka.

Bistvo Multiplierja je, da nastopa v vlogi starša, ki si svoje potomce lahko ustvarja dinamično s pomočjo povratnega klica (callback), predanega v konstruktorju. Glej primer:

protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function () {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('count', 'Število kosov:')
			->setRequired();
		$form->addSubmit('send', 'Dodaj v košarico');
		return $form;
	});
}

Zdaj lahko v predlogi enostavno pri vsakem blagu pustimo izrisati obrazec – in vsak bo resnično edinstvena komponenta.

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

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

Argument, predan v znački {control}, je v formatu, ki pravi:

  1. pridobi komponento shopForm
  2. in iz nje pridobi potomca $item->id

Pri prvem klicu točke 1. shopForm še ne obstaja, zato se pokliče njegova tovarna createComponentShopForm. Na pridobljeni komponenti (instanci Multiplierja) je nato poklicana tovarna konkretnega obrazca – kar je anonimna funkcija, ki smo jo Multiplierju v konstruktorju predali.

V naslednji iteraciji foreacha metoda createComponentShopForm ne bo več klicana (komponenta obstaja), ker pa iščemo njenega drugega potomca ($item->id bo v vsaki iteraciji drugačen), bo ponovno poklicana anonimna funkcija in nam vrnila nov obrazec.

Edino, kar preostane, je zagotoviti, da nam obrazec v košarico doda resnično tisto blago, ki ga mora – trenutno je obrazec pri vsakem blagu popolnoma enak. Pomagala nam bo lastnost Multiplierja (in na splošno vsake tovarne na komponento v Nette Frameworku), in sicer ta, da vsaka tovarna kot svoj prvi argument dobi ime tvořené komponenty. V našem primeru bo to $item->id, kar je točno tisti podatek, ki ga potrebujemo. Dovolj je torej rahlo prilagoditi tvorbu obrazca:

protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function ($itemId) {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('count', 'Število kosov:')
			->setRequired();
		$form->addHidden('itemId', $itemId);
		$form->addSubmit('send', 'Dodaj v košarico');
		return $form;
	});
}
različica: 4.0