Vice inputu formulare jako jedna komponenta

kocourPB
Člen | 47
+
0
-

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
+
+1
-

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)

Roman Halaxa
Člen | 60
+
0
-

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

kocourPB
Člen | 47
+
+1
-

@Roman Halaxa

neni zac .. tesi ma, ze to niekomu pomohlo s podobnym problemom :)