Načtení a odeslání formuláře AJAXem, lze použít snippety na výchozí stránce?

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

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
+
0
-

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
+
0
-

(Jej, nějaká chybka na fóru? Příspěvek se mi vložil dvakrát, tak jsem jeden smazal, a smazaly se oba :-) )

Původní zpráva:

Ahoj, možnou chybu vidím už v tom, že máš pro AJAX jiný layout, než pro normální aplikaci. Jaký máš k tomu důvod?

nanuqcz
Člen | 822
+
0
-

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
+
0
-

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:

  1. na stránce s přehledem kategorií udělat AJAXový požadavek na Category:add,
  2. na této AJAXem stažené stránce, která je zobrazená třeba do Fancyboxu, vyplnit formulář a odeslat ho (opět AJAXem),
  3. invalidovat ve zpracovateli formuláře snippety původní stránky (flash zprávičky, Grid), obdržet je v JSON odpovědi a
  4. 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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

Ř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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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)

darkwind
Člen | 32
+
0
-

jinak vyřešil jsem to nakonec tak, že po odeslání si do payload snippetu natáhnu znovu všechna data, která potřebuju a vypíšu je ručně…