Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
romansklenar
Člen | 655
+
0
-

Vedle nedávno nahlášené chybky tady mám další kuriozitku, se kterou se trápím už delší dobu.

Jde o ukázku component-based aplikace v Nette. Jednotlivé komponenty zapouzdřují určité logické části aplikace, presenter má jen podřadnou úlohu (jen komponentu vytvoří a vloží do šablony).

Proč vůbec psát aplikaci takto? Protože v Nette nelze adresovat ajaxové požadavky na různé presentery.
Tím, že celé tyto rutiny, která bývájí definovány v jednotlivých presenterech, přesuneme do komponent, můžeme dosánout obdoby ajaxových požadavků mezi presentery – místo presenterů se jen adresují komponenty. Jednoduché a prosté :)

Když se ale ve složitější aplikaci různé komponenty a snippety zanořují do sebe, narážím chybu, kdy místo odpovědi s obsahem snippetu dostanu jen persistentní parametry presenterů a komponent.

Jak se k chybě dopracovat?

Opět pro simulaci přikládám:

Stačí pár kroků:

  1. najedeme na demo nebo spustíme aplikaci – máme nějaký control (OfficeControl) s výpisem kanceláří a s možností přidat další kancelář
  2. vytvoříme novou kancelář přes odkaz s popiskem Add new office – do pod-snippetu se nám vykreslil znovu ten samý control, ale ve formě pro vytvoření nové kanceláře (jakoby v jiném pohledu) a se seznamem pracovníků s možností přidat další (což je pod-control EmployeeControl)
  3. zkusíme přidat dalšího pracovníka přes odkaz s popiskem Add new employee nebo v seznamu zaměstnanců změnit řazení či stránkování – a ZDE dojde k chybě – jako odezvu dostaneme jen persistentní parametry komponent
    {"state":{"employee-grid-page":null,"employee-grid-order":null,"office-grid-page":null,"office-grid-order":null}}

Abych předešel dohadům, jestli je podkomponenta EmployeeControl správně ajaxově napsaná, můžete si ji otestovat zvlášť – zde odkaz Add new employee funguje.

Nebudu to tu více rozepisovat, protože mnohem více prozradí pohled do kódu. Je využito samozřejmě posledních revizí Nette i dibi.

romansklenar
Člen | 655
+
0
-

Chyba bude nějakým způsobem souviset s podmínkami u snippetů ve vnořených komponentách, protože když v app/controls/Office/list.phtml změním

{snippet form}
@{if $signal == 'new'}
	@{? $control->renderNew()}
	<a href="{link list!}" class="ajaxlink">Show list of offices</a>
@{/if}
{/snippet}

na toto (odstraním podmínky):

{snippet form}
	@{? $control->renderNew()}
	<a href="{link list!}" class="ajaxlink">Show list of offices</a>
{/snippet}

Tak se snippety podkomponenty překreslují správně. Dále jsem se zatím nedostal.

jasir
Člen | 746
+
0
-

Musí se tedy lišit obsah vygenerovaných šablon. Porovnával jsi je?

romansklenar
Člen | 655
+
0
-

Porovnával ale chybu tam nevidím.

První:

<?php } if ($_cb->foo = $template->snippet($control, "form")) { $_cb->snippets[] = $_cb->foo; ?>
<?php } ?><?php if ($signal == 'new'): ?><?php if (SnippetHelper::$outputAllowed) { ?>
<?php } ?><?php $control->renderNew() ?><?php if (SnippetHelper::$outputAllowed) { ?>
<a href="<?php echo TemplateHelpers::escapeHtml($control->link('list!')) ?>" class="ajaxlink">Show list of offices</a>
<?php } ?><?php endif ?><?php if (SnippetHelper::$outputAllowed) { ?>
<?php array_pop($_cb->snippets)->finish(); } if (SnippetHelper::$outputAllowed) { ?>

Druhá:

<?php } if ($_cb->foo = $template->snippet($control, "form")) { $_cb->snippets[] = $_cb->foo; ?>
<?php } ?><?php $control->renderNew() ?><?php if (SnippetHelper::$outputAllowed) { ?>
<a href="<?php echo TemplateHelpers::escapeHtml($control->link('list!')) ?>" class="ajaxlink">Show list of offices</a>
<?php array_pop($_cb->snippets)->finish(); } if (SnippetHelper::$outputAllowed) { ?>
jasir
Člen | 746
+
0
-

Nějak v tom taky nic nemůžu vykoukat… Ale 100% to tam je.

David Grudl
Nette Core | 8229
+
0
-

Přiznám se, že se v té struktuře úplně neorientuju, ale zkus si stejný postup vyzkoušet s vypnutým JavaScriptem. Klikneš na Add new office, to je ok. Klikneš na stránku č.2 v datagridu a komponenta zmizí. Stejně tak dle mého zmizí i v AJAXové verzi a tudíš se nepošlou žádné snippety. Chybu bych hledal tady.

Ještě je dobré ověřit, jestli se komponenta skutečně invalidovala.

romansklenar
Člen | 655
+
0
-

Po delší době, kdy by se mi tato funkčnost hodila, jsem se k tomu vrátil a po chvilce jsem na to díky tvojí radě přišel – signál se na vnořené podkomponentě volal správně, správně se i invalidovala, ale jelikož se komponenta dostala do stavu, kdy se odkaz se signálem pro vytvoření zákazníka (employee-new) a „podsnippet“ vytvoří až po zavolání signálu (office-new), bylo třeba aby si komponenty pamatovaly, jaký signál na nich byl naposled zavolán a při volání signálů si toto info nějak předávat. Vyřešeno persistentním parametrem ve společném předkovi komponent.

Funguje to i dále rekurzivně, takže není problém do sebe zanořit 3 a více podkomponent, což je perfektní! Dá se tak poskládat krásná component-based ajaxová administrace.

Ještě pro ty co to zajímá přihazuju demo a link na opravené demo přepsané na nové featury verze 0.9.