Šablony + snipetty + ajax = věčný problém

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

Asi to všichni znáte, že když použijete rozšířenou render metodu komponenty, zadělávate si na problém při snippetech (pokud to tedy už není nějak fixlé). Protože to v appce potřebuju řešit a modal zobrazit jen za určité konstelace hvězd :) tak sem dělal různé kličky jak toho docílit. Poslední je že bych rád celou logiku rozhodování přenesl mimo presenter/component do šablony.

Takže mám šablonu presenteru:

{if $inModalWindow == TRUE}
	{define #modalWindow}
		{include #parent}
		{control passwordForm:modal}
	{/define}
{else}
	{define #content}
		{control passwordForm}
	{/define}
{/if}

Komponenta passwordForm je obyč form pro změnu hesla, netřeba řešit. Do proměnné $inModalWindow si uložím příznak zda je ta správná konstelace. Při první načtení kdy se mi zavolá akce presenteru je vše ok, když jsou podmínky modalu tak se zavolá renderModal. Jenže, teď to příjde. Šablona té komponenty má takovýto cca tvar:

modal.latte

<div class="modal">
	<form n:name="form">
		{snippet formArea}
		//..policka co se zobrazi atd...
		{/snippet}
	</form>
</div>

No a když ten form v modalu špatně vyplním tak zavolám poze překreslení snippetu formArea a všechny ostatní se validuje zpět. Po tud je to ok, jenže nette pak nějak ignoruje to že ve vykreslení komponenty je ještě parametr že, to všichni víme. Otázkou je proč? Zpracování toho signálu by přeci mělo projít přes onen presenter a jeho akci a následně pak do šablony dané akce ne? A v oné šabloně bych měl spadnout do podmínky zobraz modal a tedy {control passwordForm:modal} což se ale nestane a zavolá se obyčený render.

Takže jsem šablonu akce presenteru upravil:

{?$presenter['passwordForm']->setTemplateFile($inModalWindow ? 'modal' : 'default')}

{define #modalWindow}
	{include #parent}
	{if $inModalWindow == TRUE}{control passwordForm}{/if}
{/define}

{define #content}
	{if $inModalWindow == FALSE}{control passwordForm}{/if}
{/define}

a jednoduše na té komponentě natvrdo zavolám setTemplateFile což mě nastaví modal či default tak vše funguje (zatím) podle mých představ. Otázka tedy je proč to nette ten parametr ignoruje? Vím že tu na to bylo pár témat a většinou byl výsledek že je to by design a musíme se naučit s tím žít ;) ale přeci pokud je ten životní cyklus „identický“ tak by to snad mělo jít ošetřit ne? Zkoušel to už někdo?

Zax
Člen | 370
+
0
-

Je to celkem dlouhý a motají se do toho bloky, které moc nepoužívám, takže se mi to nechce luštit, sorry :-D

Nicméně obecně parametrizované rendery (či jak to nazvat) v komponentách (při ajaxovém požadavku) nefungují z celkem jednoduchého důvodu: je jím interface IRenderable, který zná metodu render, ale už nezná renderFoo atd. ;-) A právě s tímto interfacem pak pracuje metoda renderSnippets, která projíždí strom komponent a vykresluje ty, co jsou nevalidní.

Obecně vzato doporučuji jakékoliv parametry neposílat přes šablony, ale normálně v továrně. Nech komponentu, ať se pak sama rozhodne na základě přijatých dat jak se má vykreslit (presenter by imo měl nanejvýš řešit jestli se komponenta vykreslí, ale už ne jak). V tvém případě by dokonce mohla stačit jediná metoda třeba $control->enableModal(), která si akorát poznamená že chceme zobrazovat modál. Pokud chceš mít za každou cenu rozhodovací logiku v šabloně, pak si udělej dvě továrny createComponentPasswordForm a createComponentPasswordFormModal, v té druhé zavoláš enableModal() a v šabloně si už jen vybereš.

Jinak osobně mě tohle téma dost zajímá, s ajaxem a komponentami dělám hodně a jakmile člověk potřebuje trošku víc než základní funkcionalitu, tak prostě bohužel narazí, je to tak, ale naštěstí to není nic, bez čeho by se nedalo obejít ;-)

Editoval Zax (10. 9. 2015 11:29)

newPOPE
Člen | 648
+
0
-

Ako pise @Zax problem je v tom renderSnippets. Mal som na to davno hack, nieco v zmysle ze niekde tu https://api.nette.org/…ros.php.html#141 som vytiahol parametre daneho controlu a podla nejakeho komponenta-render=foo sa zavolal dany renderFoo. Lenze som musel v danej komponente potom ten parameter pridavat do {link ...} (co by slo asi zakryt prekrytim https://api.nette.org/…mponent.html#… nech ho prida automaticky).

akadlec
Člen | 1326
+
0
-

@Zax No hele ty bloky tam jsou jen z jednoho důvodu, pokud je to modal tak se hodi na jedno konkrétní místo v layoutu kde si to pak JS přebere a když to není modal tak se hodí zase na jiné místo kde je celý content stránky.

To že ty rendery nefungují vím ;) už sem to tu na pár místech četl, jen jsem ještě neměl odvahu na to se prokousávat nette a hledat kde se to změní od klasického renderu nesnipetího.

Ad ty parametry, toto jsou asi jediné co tam takto předávám, právě jen pro ten switch šablony, to je ohendlované v BaseControl. Ono mě tak ani nejde o to $control->enableModal() to by mě vyřešilo jen půlku řešení, spíš mě jde o to určit která konkrétní šablona se zrovna použije. A proč? Mějme třeba komponentu s tím PasswordFormem. Komponenta je definována jednoduše, má dejme tomu 3 políčka a můžu ji použít v libovolném presenteru. Jenže třeba na stráne A bych chtěl aby se použil modal_stranky_A.latte a na stránce B se pak použil jen modal.latte. Takže bych pak musel dělat pro každou variantu svou továrnu která by tu šablonu nastavila což mě příjde jako zvrácenost :D proto jsem tuhle logiku přesunul až do šablon, mimojiné taky proto aby když změním šablonu a rozhodnu se zrušit modal_stranky_A.latte to v šabloně jednoduše přepsal a nemusel hrabat do hlavní logiky :)

Výsledkem tedy pro mě je uzavřený modul který má v sobě své presenter, komponenty apod., dejme tomu i základní šablony a tento modul pak mám možnost použít v libobolném projektu a tam mu určit zda ten modal vube použiju a pokud jo tak jakou má vůbec šablonu.