Nette Documentation Preview

syntax
Reuse Forms in Multiple Places
******************************

.[perex]
How to reuse the same form in multiple places and not duplicate code? This is really easy to do in Nette and you have multiple ways to choose from.


Form Factory
============

Let's create a class that can create a form. Such a class is called a factory. In the place where we want to use the form (e.g. in the presenter), we request the [factory as dependency|/dependency-injection/passing-dependencies].

Part of the factory is the code that passes the data for further processing when the form is successfully submitted. Usually to the model layer. It also checks if everything went well, and [passes back |/forms/validation#Processing-errors] any errors to the form. The model in the following example is represented by the `Facade` class:

```php
use Nette\Application\UI\Form;

class EditFormFactory
{
	private $facade;

	public function __construct(Facade $facade)
	{
		$this->facade = $facade;
	}

	public function create(/* parameters */): Form
	{
		$form = new Form;

		// add elements to the form

		$form->addSubmit('send', 'Submit');
		$form->onSuccess[] = [$this, 'processForm'];

		return $form;
	}

	public function processForm(Form $form, array $values): void
	{
		try {
			// form processing
			$this->facade->process($values);

		} catch (AnyModelException $e) {
			$form->addError('...');
		}
	}
}
```

Of course, the factory can be parametric, i.e. it can receive parameters that will affect the appearance of the form being created.

We will now demonstrate passing the factory to the presenter. First, we write it to the configuration file:

```neon
services:
	- EditFormFactory
```

And then request it in the presenter. There also follows the next step of processing the submitted form and that is redirecting to the next page:


```php
class MyPresenter extends Nette\Application\UI\Presenter
{
	private $formFactory;

	public function __construct(EditFormFactory $formFactory)
	{
		$this->formFactory = $formFactory;
	}

	protected function createComponentEditForm(): Form
	{
		$form = $this->formFactory->create();

		$form->onSuccess[] = function (Form $form) {
			$this->redirect('this');
		};

		return $form;
	}
}
```

Since the redirection is handled by the presenter handler, the component can be used in multiple places and redirected elsewhere in each place.


Component with Form
===================

Another way is to create a new [component|/application/components] that contains a form. This gives us the ability to render the form in a specific way, for example, since the component includes a template.
Or we can use signals for AJAX communication and loading information into the form, for example for auto-completion, etc.


```php
use Nette\Application\UI\Form;

class EditControl extends Nette\Application\UI\Control
{
	public $onSave;

	private $facade;

	public function __construct(Facade $facade)
	{
		$this->facade = $facade;
	}

	protected function createComponentForm(): Form
	{
		$form = new Form;

		// add elements to the form

		$form->addSubmit('send', 'Submit');
		$form->onSuccess[] = [$this, 'processForm'];

		return $form;
	}

	public function processForm(Form $form, array $values): void
	{
		try {
			// form processing
			$this->facade->process($values);

		} catch (AnyModelException $e) {
			$form->addError('...');
			return;
		}

		// event invocation
		$this->onSave($this, $values);
	}
}
```

Next, we'll create the factory that will produce this component. Just [write its interface|/dependency-injection/factory#Component factory]:


```php
interface EditControlFactory
{
	function create(): EditControl;
}
```

And add to the configuration file:

```neon
services:
	- EditControlFactory
```

And now we can require the factory and use it in the presenter:

```php
class MyPresenter extends Nette\Application\UI\Presenter
{
	private $controlFactory;

	public function __construct(EditControlFactory $controlFactory)
	{
		$this->controlFactory = $controlFactory;
	}

	protected function createComponentEditForm(): Form
	{
		$control = $this->controlFactory->create();

		$control->onSave[] = function (EditControl $control, $data) {
			$this->redirect('this');
			// or redirect to the result of the edit, e.g.:
			// $this->redirect('detail', ['id' => $data->id]);
		};

		return $control;
	}
}
```

{{priority: -1}}
{{sitename: Best Practices}}

Reuse Forms in Multiple Places

How to reuse the same form in multiple places and not duplicate code? This is really easy to do in Nette and you have multiple ways to choose from.

Form Factory

Let's create a class that can create a form. Such a class is called a factory. In the place where we want to use the form (e.g. in the presenter), we request the factory as dependency.

Part of the factory is the code that passes the data for further processing when the form is successfully submitted. Usually to the model layer. It also checks if everything went well, and passes back any errors to the form. The model in the following example is represented by the Facade class:

use Nette\Application\UI\Form;

class EditFormFactory
{
	private $facade;

	public function __construct(Facade $facade)
	{
		$this->facade = $facade;
	}

	public function create(/* parameters */): Form
	{
		$form = new Form;

		// add elements to the form

		$form->addSubmit('send', 'Submit');
		$form->onSuccess[] = [$this, 'processForm'];

		return $form;
	}

	public function processForm(Form $form, array $values): void
	{
		try {
			// form processing
			$this->facade->process($values);

		} catch (AnyModelException $e) {
			$form->addError('...');
		}
	}
}

Of course, the factory can be parametric, i.e. it can receive parameters that will affect the appearance of the form being created.

We will now demonstrate passing the factory to the presenter. First, we write it to the configuration file:

services:
	- EditFormFactory

And then request it in the presenter. There also follows the next step of processing the submitted form and that is redirecting to the next page:

class MyPresenter extends Nette\Application\UI\Presenter
{
	private $formFactory;

	public function __construct(EditFormFactory $formFactory)
	{
		$this->formFactory = $formFactory;
	}

	protected function createComponentEditForm(): Form
	{
		$form = $this->formFactory->create();

		$form->onSuccess[] = function (Form $form) {
			$this->redirect('this');
		};

		return $form;
	}
}

Since the redirection is handled by the presenter handler, the component can be used in multiple places and redirected elsewhere in each place.

Component with Form

Another way is to create a new component that contains a form. This gives us the ability to render the form in a specific way, for example, since the component includes a template. Or we can use signals for AJAX communication and loading information into the form, for example for auto-completion, etc.

use Nette\Application\UI\Form;

class EditControl extends Nette\Application\UI\Control
{
	public $onSave;

	private $facade;

	public function __construct(Facade $facade)
	{
		$this->facade = $facade;
	}

	protected function createComponentForm(): Form
	{
		$form = new Form;

		// add elements to the form

		$form->addSubmit('send', 'Submit');
		$form->onSuccess[] = [$this, 'processForm'];

		return $form;
	}

	public function processForm(Form $form, array $values): void
	{
		try {
			// form processing
			$this->facade->process($values);

		} catch (AnyModelException $e) {
			$form->addError('...');
			return;
		}

		// event invocation
		$this->onSave($this, $values);
	}
}

Next, we'll create the factory that will produce this component. Just write its interface:

interface EditControlFactory
{
	function create(): EditControl;
}

And add to the configuration file:

services:
	- EditControlFactory

And now we can require the factory and use it in the presenter:

class MyPresenter extends Nette\Application\UI\Presenter
{
	private $controlFactory;

	public function __construct(EditControlFactory $controlFactory)
	{
		$this->controlFactory = $controlFactory;
	}

	protected function createComponentEditForm(): Form
	{
		$control = $this->controlFactory->create();

		$control->onSave[] = function (EditControl $control, $data) {
			$this->redirect('this');
			// or redirect to the result of the edit, e.g.:
			// $this->redirect('detail', ['id' => $data->id]);
		};

		return $control;
	}
}