Multiplicador: Componentes dinámicos

Una herramienta para la creación dinámica de componentes interactivos

Empecemos con un problema típico: tenemos un listado de productos en un sitio de comercio electrónico y queremos acompañar cada producto con un formulario añadir al carrito. Una forma es envolver todo el listado en un único formulario. Una forma más conveniente es utilizar Nette\Application\UI\Multiplier.

Multiplier permite definir una fábrica para múltiples componentes. Se basa en el principio de componentes anidados – cada componente que hereda de Nette\ComponentModel\Container puede contener otros componentes.

Véase el modelo de componentes en la documentación.

Multiplier se presenta como un componente padre que puede crear dinámicamente sus hijos utilizando la llamada de retorno pasada en el constructor. Véase el ejemplo:

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

En la plantilla podemos renderizar un formulario para cada producto – y cada formulario será de hecho un componente único.

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

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

Argumento pasado a {control} etiqueta dice:

  1. obtener un componente shopForm
  2. y devuelve su hijo $item->id

Durante la primera llamada de 1. el componente shopForm aún no existe, por lo que se llama al método createComponentShopForm para crearlo. A continuación, se llama a una función anónima que se pasa como parámetro a Multiplier y se crea un formulario.

En las siguientes iteraciones de foreach ya no se llama al método createComponentShopForm porque el componente ya existe. Pero como hacemos referencia a otro hijo ($item->id varía entre iteraciones), se vuelve a llamar a una función anónima y se crea un nuevo formulario.

Lo último es asegurarnos de que el formulario realmente añade el producto correcto al carrito porque en el estado actual todos los formularios son iguales y no podemos distinguir a qué productos pertenecen. Para ello podemos utilizar la propiedad de Multiplier (y en general de cualquier método de fábrica de componentes en Nette Framework) de que todo método de fábrica de componentes recibe como primer argumento el nombre del componente creado. En nuestro caso sería $item->id, que es exactamente lo que necesitamos para distinguir los productos individuales. Todo lo que hay que hacer es modificar el código de creación del formulario:

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;
	});
}
versión: 4.0