Šablony + snipetty + ajax = věčný problém
- akadlec
- Člen | 1326
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
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
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
@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.