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:
- obtener un componente
shopForm
- 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;
});
}