Načtení a odeslání formuláře AJAXem, lze použít snippety na výchozí stránce?
- dcepelik
- Člen | 36
Ahoj,
píšu aplikaci, která na back-endu hojně využívá AJAX. Na stránce
s výpisem kategorií se po kliknutí na „Přidat kategorii“ načte do
Fancyboxu stránka Category:add
, která obsahuje příslušný
formulář. Ten se zvaliduje, odešle se pomocí AJAXu a zpracuje na
serveru.
Na straně serveru se mj. nastaví flash zpráva. Volám:
<?php
...
$this->flashMessage('Category has been saved.');
if ($this->isAjax()) {
$this->invalidateControl('flashes');
}
else {
$this->redirect('default');
}
...
?>
V odpovědi serveru ale snippet flashes hledám marně. Domnívám
se, že je tomu tak proto, že Nette pošle zpět jen ty snippety, které jsou
součástí vygenerovaného výstupu (tj. jsou v šabloně nebo v layoutu).
Protože stránka Category:add
má AJAXový layout, který
neobsahuje snippet flashes, snippety se zřejmě neodešlou. (Usoudil
jsem tak ze zběžného průzkumu UIMacros).
To by se dalo vyřešit přidáním flashes do AJAXového layoutu. Problém ale narůstá v okamžiku, kdy chci na původní stránce, na které jsem klikl na „Přidat kategorii“, aktualizovat výpis kategorií.
Stavím nesmysl? Jdu na to špatně? Jsem vděčný za každou radu, po které už další nebudou potřeba.
Pěkný večer
Editoval dcepelik (21. 2. 2012 23:19)
- dcepelik
- Člen | 36
Ahoj,
důvod je zcela pragmatický. Pokud načítám některou stránku do Fancyboxu, nechci, aby se mi načetla i menu, postranní panely, patička a jiné běžné části stránky.
Myslím, že jsem tohle řešení někde viděl. Považuješ jej za špatné, popř. víš o nějakém lepším způsobu, jak výše uvedené řešit?
Editoval dcepelik (22. 2. 2012 0:14)
- nanuqcz
- Člen | 822
Pokud načítám některou stránku do Fancyboxu, nechci, aby se mi načetla i menu, postranní panely, patička a jiné běžné části stránky.
Aha, to jsem si neuvědomil, omlouvám se. Já bych to řešil čistě na
straně javascriptu. Nejdřív bych si klasicky přes AJAX natahal obsah
snippetů – včetně toho, který má být obsahem Fancyboxu – a ten pak
do fancyboxu vložil (je potřeba dát pozor na to, aby iniciativu nepřevzal
skript z jquery.nette.js
, ten by do stránky znovu vykreslil
i menu a ostatní věci)
Tedy něco takového:
<script type="text/javascript">
jQuery('a.addCategory').click(function(event){
jQuery.get({link Category:add}, '', function(data){
data.snippets['snippet--newCategory'] // obsah tohoto přidat do fancyboxu
});
event.preventDefault();
});
</script>
netestováno, drobné chybky tam určitě budou :-)
EDIT: Netvrdím, že je to best-practise. Je to ale nejlepší řešení, které mě napadlo.
Editoval nanuqcz (22. 2. 2012 0:54)
- dcepelik
- Člen | 36
Ahoj,
díky za odpověď. Nejsem si ale jist, zda si zcela rozumíme.
Problém není s JavaScriptem ani se zpracováním snippetů, problém je,
že se vůbec neodešlou. Neodešlou se proto, že nejsou součástí stránky
Category:add
(domněnka). Otázka tedy zní, zda lze:
- na stránce s přehledem kategorií udělat AJAXový požadavek na
Category:add
, - na této AJAXem stažené stránce, která je zobrazená třeba do Fancyboxu, vyplnit formulář a odeslat ho (opět AJAXem),
- invalidovat ve zpracovateli formuláře snippety původní stránky (flash zprávičky, Grid), obdržet je v JSON odpovědi a
- vykreslit je.
Problém je se třetím krokem, avšak mně se zdá, že to, co navrhuješ ty, se týká zejména prvního, druhého a čtvrtého. Lze v rámci akce invalidovat i ty snippety, které nejsou součástí šablony dané akce? A pokud ne, jak to obejít, aby bylo umožněno výše uvedené?
Přesto velice děkuji za pomoc.
- Gaprielko
- Člen | 42
Zdravim,
riešim podobný problém, čo sa týka invalidace snippetov mimo šablony akcie používam:
<?php
..
$this->presenter->invalidateControl('flashes');
..
?>
čo invaliduje snippety v @layoute. Problém mam však s načítanim js súborov.. po takejto invalidacii flash správ sa mi správy síce zobrazia ok, avšak nefunguje js a nezmiznu.. ak do invalidovaného snippetu dám celý js kód, tak to funguje, ak len nalinkujem js súbor tak nie.. rovnaký problém mám napr. aj pri LiveFormValidation po ajaxovom odoslaní požiadavky na dynamickú zmenu formulára (pridanie/odobranie nejakých prvkov).. akonáhle sa ajaxom updatnem formulár, nefunguje js.. ako na to?
- Vojtěch Dobeš
- Gold Partner | 1316
No, asi takto: „aplikace“ snippetů (tedy to že se patřičné
<div>
y s patřičnými IDčky projdou a vymění se jejich
obsah za ten nový vrácený v payloadu) přepíše DOM a tudíž přepíše
i dříve navázané callbacky na události. Je tedy třeba je buď navázat
znovu, anebo je napoprvé zavolat pomocí live()
(nevím, jestli
v jQuery ještě je). Faktem je, že ta první varianta je úspornější. Aby
se však člověk vyhnul nutnosti rvát ten Javascript přímo do šablony do
snippetu (což není hezký, ani úsporný, ani optimalizovaný), je lepší si
upravit jquery.ajax.js
nebo jak se ten skriptík pro Nette jmenuje
a v reakci success
si znovu zavolat potřebný kód (jako nějakou
validaci formulářů, pokud snippet formulář obsahuje atd.).
- Aearsis
- Člen | 57
Koukám že ti tady nikdo nerozumí, tak se o to pokusím i já.
Nemá fancybox nějaký event „dialogClosed“ ? Pak by šlo po jeho uzavření přes js „kliknout“ na AJAXový odkaz „refresh“ na té zadní stránce, který mj. může být klidně viditelný. To vyvolá klasickej AJAX request na původní stránku, a měl by vše překreslit.
- Vojtěch Dobeš
- Gold Partner | 1316
Aearsis Můžu se zeptat, jak to souvisí s přepsáním nabindovaných událostí při aplikaci snippetů a jak to řešit?
- darkwind
- Člen | 32
Řeším něco podobného, a taky si s tím už nevím rady.
mám seznam stránek obalený v {snippet pagesContainer}…{/snippet} a
tlačítko „přidat“.
při kliku na „přidat“ se mi načte jquery dialog, do kterého pomocí
.load() načtu obsah akce Page:add, která mi vykreslí formulář. Ten potom
zpracovávám pomocí ajaxu, což funguje – data se odešlou a vloží do
databáze.
v callback savePage mám na konci:
$this->invalidateControl();
$this->sendPayload();
v konzoli se mi zobrazí, že request proběhne v pořádku, ale odezva je
pouze prázdní „{}“
Když si vypíšu isControlInvalid pomocí
$this->payload->stav = $this->isControlInvalid("pagesContainer");
,
tak mi to vrátí {"stav":true}
… ale data upraveného seznamu
stránek ve snippetu to nezmění a ani vlastně nevrací v odezvě…
co dělám špatně?
- petr.pavel
- Člen | 535
Zkus
$this->invalidateControl("pagesContainer")
.
Edit: Pardon, přehlédl jsem, že ti
isControlInvalid("pagesContainer")
vrací true, takže tím
to není.
Nejsem si jistý, ale není sendPayload()
jen pro případy, že
si $this->payload
plníš ručně sám?
Každopádně, snippety by se ti měly samy posílat v payload díky
autodetekci AJAXu. Akci/render presenteru nech doběhnout do konce a payload se
ti naplní a odešle sám. Já sendPayload() vůbec nepoužívám, v presenteru
nemám žádné zvláštní chování pro AJAX a ne-AJAX.
Editoval petr.pavel (11. 5. 2012 17:22)
- darkwind
- Člen | 32
No, to jsem zkoušel vlastně úplně na začátku. Pak jsem si někde přečetl, že když budu invalidovat celý ten presenter, tak by to mělo invalidovat všechny snippety uvnitř něj, tak jsem to zkusil i bez toho cílení.
Mám podezření, že se to snaží invalidovat ten snippet pagesContainer
v šabloně pro akci Pages:add, která je načítaná ajaxem do divu.
Ale ten snippet je uvnitř šablony pro tu nadřazenou akci, Pages:default
EDIT: reakce na tvoji změnu
když tam nedám ten sendPayload, tak mi to v odezvě dotazu vrátí prázdné
{"state":[]}
, což je vlastně úplně stejný stav…
Editoval darkwind (11. 5. 2012 17:28)
- Vojtěch Dobeš
- Gold Partner | 1316
No jasně… ten kus HTML kódu, co si načítáš pomocí
load()
, bude obsahovat odkazy vedoucí na Page:add
, a
proto se na tuhle adresu taky posílá AJAX request. Jak to řešit mě z hlavy
nenapadá…
Řešením bude asi trochu to předělat (případně mít obsah toho snippetu stejnej jak v default, tak v add).
Editoval vojtech.dobes (11. 5. 2012 18:13)
- Vojtěch Dobeš
- Gold Partner | 1316
Snippety se do payloadu samozřejmě dostanou jen tehdy, pokud jsou v šabloně aktuálního view. Pokud k šabloně nejsou, invalidateControl sice nijak nezařve, ale nic se nestane.
- darkwind
- Člen | 32
No, mě ještě napadlo, že bych ten snippet dal i do toho view Page:add (a tam bych ho skryl pomocí display:none… trochu prasárna teda ale nevadí, protože někde jsem v návodech nebo na foru četl, že je jedno, kde to je, on si to přeluská a upraví to třeba i na dvou místech.
Jenomže, jakmile jsem do šablony pro :add dal {snippet pagesContainer} …html obsah… {/snippet}, tak mi ta šablona najednou začala dědit i od nadřazené šablony a vypsala mi i hlavičku, menu, apod. Takže jsem se tímto směrem neubíral vůbec dál.
Jaké tedy jsou možnosti? Je možné si v payload vrátit ten požadovaný obsah, který by měl být ve snippetu a pomocí javascriptu si to vypsat „ručně“ do toho divu?
- Vojtěch Dobeš
- Gold Partner | 1316
Přidání snippetu do šablony určitě nezpůsobilo dědění od layoutu, od toho se už určitě dědilo i předtím.
Myslím, že už mě řešení napadlo – prostě u invalidace toho
snippetu zavolej $this->setView('default')
, případně natvrdo
$this->template->setFile(... cesta k šabloně pro default ...);
.
- darkwind
- Člen | 32
No, to způsobí, že jako view nastaví default, ale už to do toho defaultu neodešle potřebná data jako v původní funkci default, musel bych ji celou zduplikovat při zpracování formuláře… Já asi nepotřebuju znovu nastavit :default, ale spíš provést funkcionalitu :default a vykreslit ta data dovnitř do {snippet pagesContainer}
a jinak věřím, že u toho s tím snippetem asi víš, o čem mluvíš… ale ono to fakt do té doby, než jsem tam ten {snippet} dal, tak vykreslilo pouze obsah add.latte, a pokud jsem ho tam dal, tak to vykreslilo i s nadřazenou @layout.latte
Jak se to teda má správně řešit u modal boxů? Mám ten přidávací formulář vykreslit už v :default a skrytý a úplně vypustit akci :add? A potom jen pomocí toggle zobrazit modal box? To už je ten modal potom jenom spíš na efekt, protože budu muset vše, co vykresluju v :add, umístit už do :default
Editoval darkwind (11. 5. 2012 20:47)