Současné překreslení stejných komponent

Sniclman
Člen | 10
+
0
-

Ahoj, potřeboval bych poradit jak současně překreslit více stejných komponent po odeslání formuláře.
Překreslní by fungovalo v případě použití jedné komponenty na stránce, nicméně pokud je komponenta použita vícekrát, překreslí se vždy pouze první.
Obalovat celou stránka/šablonu snippetem mě nepřijde efektivní, protože se musí zpracovat mnohem více dat a mezi komponentami jsou další komponenty.
Komponenta sama o sobě nepotřebuje vstupní parametry.

V presenteru mám funkce:

// vytvoření komponenty
protected function createComponentMojeSuperkomponenta()
{
  $control = $this->mojeSuperkomponentaFactory->create();
  $control->setLang( $this->locale );
  return $control;
}

// zpracování formuláře
public function formularSucceeded( Form $form )
{
  if ( $this->isAjax() )
  {
    $this['mojeSuperkomponenta']->redrawControl();
  }
  else
  {
    $this->redirect( 'this' );
  }
}

V latte šabloně to vypadá nějak takhle:

<header>
	{control mojeSuperkomponenta}
</header>
<div>
 {control formular}
</div>
<div>
	...a spousta dalších formulářů, O5/grida a další serepetičky...
</div>
<footer>
	{control mojeSuperkomponenta}
</footer>

V šabloně latte komponenty mojeSuperkomponenta:

{snippet}
	<div>Hodnota: {$nejakaPromenaKomponenty}</div>
{/snippet}
Polki
Člen | 553
+
+3
-

Koukni se na výsledný HTML kód.
Vsadím se, že že pokud se tvůj snippet jmenuje třeba ahoj, tak v html budou 2 takovéto řádky:

<div id="snippet-mojeSuperkomponenta-ahoj">

No a snippety se překreslují tak, že se ze serveru vrátí obsah snippetu, spáruje se s daným ID snippetu a to se překreslí.
No a jelikož JS ctí pravidla návrhu HTML a to, že ID musí být unikátní, tak tedy překreslí pouze první výskyt daného ID snippetu, jelikož ví, že díky unikátnosti už jich více na stránce být nesmí.

Tím ale, že používáš tu stejnou komponentu, tak děláš to, že jsi vytvořil duplikát, který má stejné ID.

Řešení je, nepoužívat tu stejnou komponentu. Jinými slovy použít například Multiplier, nebo přejmenovat továrničku.

protected function createComponentMojeSuperkomponentaHeader()
{
  $control = $this->mojeSuperkomponentaFactory->create();
  $control->setLang( $this->locale );
  return $control;
}

protected function createComponentMojeSuperkomponentaFooter()
{
  $control = $this->mojeSuperkomponentaFactory->create();
  $control->setLang( $this->locale );
  return $control;
}

a potom v šabloně:

<header>
	{control mojeSuperkomponentaHeader}
</header>
<div>
 {control formular}
</div>
<div>
	...a spousta dalších formulářů, O5/grida a další serepetičky...
</div>
<footer>
	{control mojeSuperkomponentaFooter}
</footer>

NEBO

protected function createComponentMojeSuperkomponenta()
{
	$factory = $this->mojeSuperkomponentaFactory;
	$locale = $this->locale;
	return new Multiplier(function () use ($factory, $locale) {
	  	$control = $factory->create();
  		$control->setLang( $locale );
  		return $control;
	});
}

a potom v šabloně:

<header>
	{control mojeSuperkomponenta-header}
</header>
<div>
 {control formular}
</div>
<div>
	...a spousta dalších formulářů, O5/grida a další serepetičky...
</div>
<footer>
	{control mojeSuperkomponenta-footer}
</footer>

No a pokud se ti toto nelíbí, tak je ještě možnost napsat si vlastní obslužný JS.

EDIT 1:
A samozřejmě budeš muset i změnit překreslování snippteů:

public function onSuccess()
{
	...
	$this['mojeSuperkomponentaHeader']->redrawControl();
	$this['mojeSuperkomponentaFooter']->redrawControl();
	...
}

NEBO

public function onSuccess()
{
	...
	$this['mojeSuperkomponenta-header']->redrawControl();
	$this['mojeSuperkomponenta-footer']->redrawControl();
	...
}

Editoval Polki (26. 5. 2021 12:40)

Sniclman
Člen | 10
+
0
-

Díky za info k IDéčkům snippetů. Měnit obslužný JS nechci, to mě nepřijde jako správné řešení :-).
Nejlepší by tedy bylo použití Multiplikátoru, což by umožnilo použití komponenty kdekoliv a kolikrát bych chtěl.

Je nějaká možnost jak v presenteru získat všechny použité komponenty?

<header>
	{control mojeSuperkomponenta-header}
</header>
<div>
 {control formular}
</div>
<div>
	...a spousta dalších formulářů, O5/grida a další serepetičky...
</div>
<footer>
	{control mojeSuperkomponenta-footer}
	...
	{control mojeSuperkomponenta-footerDvojka}
</footer>

něco jako:

public function onSuccess()
{
	$komponenty = $this->getAllComponents( 'mojeSuperkomponenta' ); // vracelo by array s objekty komponent
	foreach( $komponenty as $komponenta )
	{
		$komponenta->redrawControl();
	}
}
jiri.pudil
Nette Blogger | 1028
+
+3
-

Určitě, Multiplier je taky komponenta:

foreach ($this['mojeSuperkomponenta']->getComponents() as $component) {
	$component->redrawControl();
}
Sniclman
Člen | 10
+
0
-

Tak jsem zkusil metodu getComponents ale nic mě nevrátí. V dumpu je prázdná.
Ještě bych mohl doplnit, že používám Nette 2.4.

<header>
	{control mojeSuperkomponenta-aaa}
</header>

{control mojeSuperkomponenta-bbb}

<footer>
	{control mojeSuperkomponenta-ccc}
</footer>
  protected function createComponentMojeSuperkomponenta()
  {
    return new Multiplier( function( $name){
      $control = $this->mojeSuperkomponentaFactory->create();
      $control->setLang( $this->locale );
      return $control;
    });
  }

public function onSuccess()
{
    bdump( $this['mojeSuperkomponenta'] );
    foreach( $this['mojeSuperkomponenta']->getComponents() as $key => $comp )
    {
      bdump( $key );
      bdump( $comp );
    }
}

jiri.pudil
Nette Blogger | 1028
+
+1
-

Ajo, ty komponenty se ti nejspíš vytvářejí až při renderu, takže při zpracování formuláře ještě neexistují. V takovém případě se myslím neobejdeš bez toho, aby sis někde držel seznam těch názvů :|

Polki
Člen | 553
+
0
-

Seznam názvů si můžeš držet v nějakém poli/proměnné/generátoru apod.

Takže i v latte můžeš vykreslovat komponenty cyklem a v success metodě můžeš cyklem renderovat.