Zamezení vykonání těla renderXXX při AJAXu
- joe
- Člen | 313
Ahoj,
mám celkem „problém“ při přidávání podpory AJAXu na stránky. Všechno mi sice funguje, ale řešení se mi zdá celkem krkolomné. Špatně se mi to popisuje, snad to pochopíte z příkladu:
Představte si stránku, jejíž načtení bude vyžadovat nějaké náročné dotazy na DB a bude také obsahovat možnost vložení komentáře a dalších věcí na podobném principu – to bych chtěl mít přes AJAX.
Kód by tedy vypadal nějak takto:
public function renderDefault() {
// .
// . různé volání metod modelů (mohou obsahovat náročné dotazy)
// .
$this->template->comments = Comments::get();
}
Dál taky továrničku na vytvoření formuláře a metodu pro jeho zpracování:
public function addCommentFormSubmitted(AppForm $form) {
// vložení komentáře je ok
$this->flashMessage('Odeslano');
if($this->isAjax()) {
$this->invalidateCotrol('flashes');
// může následovat vložení dat do payloadu pro další zpracování
// $this->payload->...
} else {
$this->redirect('this');
}
}
A teď ten problém je, že i při AJAXově odeslaném formuláři se znovu
vykoná vše v metodě renderDefault()
, tedy i to, co už znovu
načítat NECHCI. Zřejmě asi nemůžu nijak ukončit požadavek třeba pomocí
$this->sendPayload()
, protože potřebuju invalidovat snippety a
do JavaScriptu dostat jejich výstup:
Např. při vložení toho komentáře vrátím ty nejnovější uložené od posledně zobrazeného (ukládám si ID posledního zobrazeného komentáře v hidden poli ve formuláři).
Tím tak v každé takové metodě renderXXX
musím ověřovat,
jestli se jedná o AJAX požadavek nebo ne, pokud ano, tak jestli je odeslaný
ten konkrétní formulář a teprve potom vložit potřebná data do šablony
(ty nejnovější komentáře), aby mi přišly do JavaScriptu.
Pokud bych na tu samou stránku přidal ještě například anketu, AJAXové
hlasování by bylo přes signál handleXXX
, kde bych si musel
nastavit nějaký příznak (atribut) třídy, že se má při renderování
něco změnit. A v té metodě renderDefault
opět ověřovat,
jestli se jedná o AJAX požadavek a jestli je příznak nastavený a teprve
potom zapsat do šablony, abych měl všechny zápisy
$this->template->...
v render metodách.
Nevím, ale přijde mi to celkem nepřehledné. Nenapadá vás lepší způsob nebo to jinak nejde? Nešlo by invalidovat snippety, aniž by se provedlo to, co je v render metodách (ale to je asi zase hloupost (?))
Díky za odpovědi
- joe
- Člen | 313
Díky za reakci, ale tak to přece není řešení. Můj problém není tahat data až při invalidaci, ale zamezení toho ostatního, co právě při AJAXových volání pak zahodím. Tedy to, co se skrývá pod komentářem
// různé volání metod modelů (mohou obsahovat náročné dotazy)
Navíc mít pak načítání přímo v šabloně, to si myslím, že bych to tím akorát zase víc znepřehlednil.
- Mikulas Dite
- Člen | 756
Řešení od mkoubik je ideální, protože se tím zrychlí každý požadavek na cache, ne jenom ajaxové requesty.
Otázka je, jestli když Nette vytváří snippet, tak zahazuje co nechce, nebo kreslí jenom něco.
Načítání v šabloně nepřehledné imho není, Object a jeho magický property access umožní psát všechny gettery krátce.
- Ondřej Mirtes
- Člen | 1536
Mně se to volání SQL ze šablony nelíbí, protože když při tom něco v databázi zhavaruje, uživatel skončí s napůl rozbitým výstupem (uprostřed normálního HTML se začne vypisovat ErrorPresenter).
- Tharos
- Člen | 1030
@Ondřej Mirtes: Pozor, aby tu nezačala další nekončící debata, kde zachytávat chyby. :) Vždycky jsem měl podobný postoj, jako Ty, ale tento lazy přístup má něco do sebe. Jasnou výhodou je, že web má tak lepší odezvu. Hlavní nevýhodu jsi uvedl, ale vezmi si, že k chybě, při které se řekněme hlavní obsah stránky z databáze vydoluje a o pár mikrosekund později nějaký přehled novinek v bočním sloupci už ne, dojde například při jednom z 5000 requestů. Není pak lákavé mít pro 4999 uživatelů rychlejší aplikaci za cenu toho, že jeden chudák obdrží nedokonalý nevalidní výstup?
- joe
- Člen | 313
22 napsal(a):
když je to takovej problém, tak proč si ty věci nedáš do action fáze?
Action fáze taky nic neřeší, ne? To už „je jedno“, jestli budu podmínkovat v action nebo render fázi. Přijde mi to stejné. Mně by jen zajímalo, jestli pro to není nějaký lepší způsob.
mkoubik napsal(a):
Vytvoř si metodu…
I když bych takovou metodu měl, pak u všech render fází (pokud v nich něco bude) musim stejně rozlišit, jestli jde o AJAX a nebo ne.
@Mikulas Dite:
K pořádnému promyšlenému cachování jsem se zatím moc nedostal.
Otázka je, jestli když Nette vytváří snippet, tak zahazuje co nechce, nebo kreslí jenom něco.
Celkem by se mi líbilo, kdybych v tom signálu mohl zakončit v případě AJAXu $this->sendPayload() s tím, že dojde i k invalidování snippetů a odeslání na výstup. Nemusel bych se pak starat o to, co mám v další render fázi. Takhle vlastně musím mít podmínky na AJAX jak v signálu, tak v render fázi.
@Ondřej Mirtes &
@Tharos:
Rád bych řešil jen to, na co jsem se v úvodu ptal :-) a nechtěl bych to
odvracet na téma, kde zachytávat chyby.
Za sebe bych je ale chtěl zachytávat ještě dřív než v šabloně –
z důvodu co napsal Ondra, i přesto, že k tomu třeba nikdy
nemusí dojít.
Takže asi jiný způsob něž if($this->isAjax()) nebude? Nebo jak podobné věci řešíte?
- Mikulas Dite
- Člen | 756
Tak obecně to řeší právě cache. Pokud se o výstup žádá poprvé, to zdržení na náročném dotazu tam bude a nic se s tím nadělat nedá.
- joe
- Člen | 313
To je pravda, to mi v tu chvíli nedošlo jak jsi psal o cachování. Ale zase je hloupost cachovat vše a třeba některé náročné dotazy moc cachovat nemusí jít (musí být aktuální). Mně šlo čistě o to, jak nevykonávat to, co je v render fázích při AJAX požadavcích s invalidováním snippetů (takže to teď asi přes render musí projít, aby se ty snippety odeslaly do JS a jinak než s pomocí podmínek toho asi nedosáhnu).