Vice inputu formulare jako jedna komponenta

- kocourPB
 - Člen | 47
 
Zdravim,
aktualne riesim jeden use-case, kedy sa nam vo viacerych formularoch opakuju 3 stejne inputy. Z tychto troch opakujucich inputov by som chcel vytvorit samostatnu komponentu, ktora by mala vlastnu classu napr. SameInputsComponent (extend mozna z \Nette\Forms\Controls\BaseControl ? … nevim) a mala by vlastnu latte sablonu, kde by boli manualne vykreslene tieto inputy.
Vo formularu by som zavolal nieco ako:
$form->addComponent($this->sameInputComponentFactory->create(), ...);
Hladal som nejaky priklad na fore, ale nic podobne som nenasiel. Riesili ste niekto podobny use-case? Ak ano, tak ako? Diky za rady. :)

- kocourPB
 - Člen | 47
 
Ahoj,
tak nakoniec som zo seba vymacknul toto funkcne riesenie. Snad to niekoho inspiruje, pripadne pomoze. ;)
ScheduleComponent.php
<?php
declare(strict_types=1);
use Nette\Forms\Controls\BaseControl;
use Nette\Utils\ArrayHash;
interface IScheduleFormComponent
{
  /** @return ScheduleFormComponent */
  function create();
}
class ScheduleComponent extends BaseControl
{
  /** @var string */
  protected $formContainerName;
  /**
   * @param \Form $form
   */
  public function attached($form)
  {
    $formContainer = $form->addContainer($this->formContainerName);
    $formContainer->addCheckbox('isNonstop', _('Vždy'));
    /** @var array $schedule */
    $schedule = $form[$this->formContainerName];
    $dayArray = explode(',', _('PO, ÚT, ST, ČT, PÁ, SO, NE'));
    for ($dayOfWeek = 0; $dayOfWeek < 7; $dayOfWeek++) {
      $dayName = 'days_' . $dayOfWeek;
      $formContainer->addCheckbox($dayName, trim($dayArray[$dayOfWeek]));
      $startName = 'start_' . $dayOfWeek;
      $formContainer->addText($startName, _('Od:') . ' ', 5, 5)
        ->setHtmlAttribute('class', 'schedule-input-start')
        ->addConditionOn($schedule[$dayName], \Form::EQUAL, true)
        ->addRule(\Form::PATTERN, _('Zadejte prosím čas "Od" ve formátu 00:00.'), '^\d{1,2}:\d{2}$');
      /** @var BaseControl $from */
      $from = $formContainer[$startName];
      $from->getControlPrototype()->id('schedule_start_' . $dayOfWeek);
      $endName = 'end_' . $dayOfWeek;
      $formContainer->addText($endName, _('Do:') . ' ', 5, 5)
        ->setHtmlAttribute('class', 'schedule-input-end')
        ->addConditionOn($schedule[$dayName], \Form::EQUAL, true)
        ->addRule(\Form::PATTERN, _('Zadejte prosím čas "Do" ve formátu 00:00.'), '^\d{1,2}:\d{2}$');
      /** @var BaseControl $to */
      $to = $formContainer[$endName];
      $to->getControlPrototype()->id('schedule_end_' . $dayOfWeek);
    }
    parent::attached($form);
  }
  public function getControl()
  {
    $latte = new \Latte\Engine;
    $template = new \Nette\Bridges\ApplicationLatte\Template($latte);
    $template->setFile(__DIR__ . '/ScheduleComponent.latte');
    $template->caption = $this->caption;
    $form = $this->getForm();
    $template->form = $form;
    $template->formContainerName = $this->formContainerName;
    $control = \Nette\Utils\Html::el('span');
    $control->setHtml($template->__toString());
    return $control;
  }
  public function setCaption(string $caption): ScheduleFormComponent
  {
    $this->caption = $caption;
    return $this;
  }
  public function setFormContainerName(string $formContainerName): ScheduleFormComponent
  {
    $this->formContainerName = $formContainerName;
    return $this;
  }
}
ScheduleComponent.latte
<tr class="conditions">
  <td class="form_td_label"><label>Spustit:</label></td>
  <td>
    {$form[$formContainerName]['isNonstop']->control}
    {$form[$formContainerName]['isNonstop']->label}
  </td>
</tr>
<tr n:for="$i=0; $i < 7; $i++" class="conditions schedule_row">
  <td></td>
  <td>
    <span class='schedule_days'>
      {$form[$formContainerName]['days_'.$i]->control}
      {$form[$formContainerName]['days_'.$i]->label}
    </span>
    {$form[$formContainerName]['start_'.$i]->label}
    {$form[$formContainerName]['start_'.$i]->control}
    {$form[$formContainerName]['end_'.$i]->label}
    {$form[$formContainerName]['end_'.$i]->control}
  </td>
</tr>
config.neon
services:
	- IScheduleFormComponent
pouzitie v existujucom formularu napr. v presenteru
class CalendarPresenter {
  /** @var IScheduleFormComponent @inject */
  public $scheduleFormComponent;
  // ...
  protected function createComponentEditForm()
  {
    $form = new Form;
	// ...
	$scheduleComponent = $this->scheduleFormComponent->create()
      ->setFormContainerName('schedule')
      ->setCaption('Rozvrh');
	$form->addComponent($scheduleComponent, 'scheduleComponent');
	// ...
	return $form;
  }
  // ...
}
edit: upravene s vyuzitim tovarny/factory ;o)
Editoval kocourPB (14. 3. 2019 15:58)

- deleted
 - Člen | 61
 
kocourPB napsal(a):
Ahoj,
tak nakoniec som zo seba vymacknul toto funkcne riesenie. Snad to niekoho inspiruje, pripadne pomoze. ;)
ScheduleComponent.php
<?php declare(strict_types=1); use Nette\Forms\Controls\BaseControl; use Nette\Utils\ArrayHash; class ScheduleComponent extends BaseControl { /** @var string */ protected $formContainerName; public function __construct(string $formContainerName, $caption = null) { $this->formContainerName = $formContainerName; parent::__construct($caption); } /** * @param \Form $form */ public function attached($form) { $formContainer = $form->addContainer($this->formContainerName); $formContainer->addCheckbox('isNonstop', _('Vždy')); /** @var array $schedule */ $schedule = $form[$this->formContainerName]; $dayArray = explode(',', _('PO, ÚT, ST, ČT, PÁ, SO, NE')); for ($dayOfWeek = 0; $dayOfWeek < 7; $dayOfWeek++) { $dayName = 'days_' . $dayOfWeek; $formContainer->addCheckbox($dayName, trim($dayArray[$dayOfWeek])); $startName = 'start_' . $dayOfWeek; $formContainer->addText($startName, _('Od:') . ' ', 5, 5) ->setHtmlAttribute('class', 'schedule-input-start') ->addConditionOn($schedule[$dayName], \Form::EQUAL, true) ->addRule(\Form::PATTERN, _('Zadejte prosím čas "Od" ve formátu 00:00.'), '^\d{1,2}:\d{2}$'); /** @var BaseControl $from */ $from = $formContainer[$startName]; $from->getControlPrototype()->id('schedule_start_' . $dayOfWeek); $endName = 'end_' . $dayOfWeek; $formContainer->addText($endName, _('Do:') . ' ', 5, 5) ->setHtmlAttribute('class', 'schedule-input-end') ->addConditionOn($schedule[$dayName], \Form::EQUAL, true) ->addRule(\Form::PATTERN, _('Zadejte prosím čas "Do" ve formátu 00:00.'), '^\d{1,2}:\d{2}$'); /** @var BaseControl $to */ $to = $formContainer[$endName]; $to->getControlPrototype()->id('schedule_end_' . $dayOfWeek); } parent::attached($form); } public function getControl() { $latte = new \Latte\Engine; $template = new \Nette\Bridges\ApplicationLatte\Template($latte); $template->setFile(__DIR__ . '/ScheduleComponent.latte'); $template->caption = $this->caption; $form = $this->getForm(); $template->form = $form; $template->formContainerName = $this->formContainerName; $control = \Nette\Utils\Html::el('span'); $control->setHtml($template->__toString()); return $control; } }ScheduleComponent.latte
<tr class="conditions"> <td class="form_td_label"><label>Spustit:</label></td> <td> {$form[$formContainerName]['isNonstop']->control} {$form[$formContainerName]['isNonstop']->label} </td> </tr> <tr n:for="$i=0; $i < 7; $i++" class="conditions schedule_row"> <td></td> <td> <span class='schedule_days'> {$form[$formContainerName]['days_'.$i]->control} {$form[$formContainerName]['days_'.$i]->label} </span> {$form[$formContainerName]['start_'.$i]->label} {$form[$formContainerName]['start_'.$i]->control} {$form[$formContainerName]['end_'.$i]->label} {$form[$formContainerName]['end_'.$i]->control} </td> </tr>pouzitie v existujucom formularu
protected function createComponentEditForm() { $form = new Form; // ... $form->addComponent(new ScheduleComponent('schedule', 'Kalendar'), 'scheduleComponent'); // ... return $form; }
Děkuji za sdílení :D Nakopnul jsi mě správným směrem jak k inputu přiřadit vlastní šablonu tak aby to renderer špatně nepobral. Už jsem to teda udělal tak že jsem ke svému inputu dal složku se závistlostmi a řeším to celé v javascriptu ale i tak, to se do budoucna bude hodit až budu vytvářet jiný :D