Nette\Forms - jak vytvořit a použít custom input ve formulářích 11/08/2017

Ukážeme si, jak vytvořit a použít custom input v Nette formulářích pomocí navěšovacích metod, vlastního formuláře a přímo ve formuláři.

Téměř v každém projektu dospějeme do stavu, kdy je potřeba vytvořit si vlastní typ inputu. V mých aplikacíh se často opakuje DateInput, DateTimeInput a např. ImageControl.

Nechceme neustále vynalézat kolo, tak se pokusím řadu z nejpouživanějších přidat do contributte/forms. Než to tak bude, pojďme se podívat jaké máme možnosti.

Napadají mě 3 varianty:

  1. Instant Usage
  2. Extension Method
  3. Custom Form

Než přejdeme na ukázky, tak si vytvoříme custom input.

class EmailInput extends Nette\Forms\Controls\TextInput
{
 
  public function __construct($label = null)
  {
    parent::__construct($label);
    $this->setType('email');
  }

  public function setAlert($message)
  {
    $this->setRequired(TRUE);
    $this->addRule(Nette\Forms\Form::EMAIL, $message);
  }

}

Instant Usage

Náš EmailInput použijeme ve formuláři přímo a to zavoláním metody addComponent($name, $component), poté input získáme metodou getComponent($name).

Protože Nette\Forms\Container implementuje ArrayAccess, lze inputy navěšovat i přes $form[$name] a obdobně získat přes $form[$name].

class EmailPresenter extends Nette\Application\UI\Presenter
{

  protected function createComponentEmailForm() 
  {
      $form = new Form();
      
      $form->addComponent('email', new EmailInput('My e-mail'));
      $form->getComponent('email')->setAlert('Please type valid e-mail address');
      
      // ====

      $form['email'] = new EmailInput('My e-mail');
      $form['email']->setAlert('Please type valid e-mail address');

      return $form;
  }

}

Osobně se mi to ale tolik nelíbí, daleko víc cool je využívat $form->add<input>. S tím nám pomůžou následující 2 techniky.

Extension Method

Extension method je nanásilná technika, která nám umožní “navěsit” extra input do naších formulářů.

// bootstrap.php || CompilerExtension

Nette\Forms\Container::setExtensionMethod(
    Nette\Forms\Container::class, 
    'addEmailInput', 
    function(Nette\Forms\Container $container, $name, $title = 'Your e-mail address') {
        return $container[$name] = new EmailInput($title);
    }
);

Využijeme k tomu Nette\Forms\Container::setExtensionMethod, která navěsí extra metodu addEmailInput, kterou můžeme použít při sestavování formulářů. setExtensionMethod je vhodné zavolat v souboru bootstrap.php nebo lépe, a to v CompilerExtension. Důležité je zavolat tyto metody před použitím ve formulářích.

class EmailPresenter extends Nette\Application\UI\Presenter
{

  protected function createComponentEmailForm() 
  {
      $form = new Form();
      $form->addEmailInput('email', 'My e-mail')
        ->setAlert('Please type valid e-mail address');

      return $form;
  }

}

Do objektu EmailInput se předá titulek My e-mail. Pokud bychom title neuvedli, vezme se předdefinovaná Your e-mail address.

Podobně můžeme navěšovat i nové metody do Nette\Forms\Controls\BaseControl a tím si rozšířit naše komponenty o super vlastnosti.

Custom Form

use Nette\Forms\Form;

class EmailForm extends Form
{

    public function addEmailInput($name, $title = 'Your e-mail address')
    {
        return $this[$name] = new EmailInput($title);
    }

}

class EmailPresenter extends Nette\Application\UI\Presenter
{

  protected function createComponentEmailForm() 
  {
      $form = new EmailForm();
      $form->addEmailInput('email', 'My e-mail')
        ->setAlert('Please type valid e-mail address');

      return $form;
  }

}

Doufam, že jsem vám alespoň trochu přiblížil, jak lze tvořit a používat custom inputy v Nette formulářích. Pokud znáte další postupy, budu rád, když je uvedete v komentářích.