Jak z komponenty na AJAXový request odpovědět pouze řetězcem či jsonem
- tobice
- Člen | 30
Mám komponentu pro upload obrázků. Komponenta obsahuje standardní formulář pro nahrávání souborů a synchronně funguje vše v pořádku. Chtěl bych nicméně nasadit nějaký pohodlnější JavaScriptový plugin pro asynchronní nahrávání, např. Dropzone. Problém je, že po nahrání obrázku je serverem pochopitelně vrácena celá stránka, resp. invalidované snippety jako json, jen s překreslenou komponentou. Já bych nicméně potřeboval, aby při asynchronních requestech vracel server jen prázdnou stránku či pouze chybovou hlášku při selhání.
V samotném presenteru by šlo toto řešit, je tam k dispozici isAjax(), mám svobodu při vyrábění HttpResponse atd. S komponentou je ale přirozeně problém ten, že je zcela uzavřená do sebe a o veškerou logiku se stará sama. V presenteru ji pouze nainicializuji a zpracování signálu včetně error handlingu si řeší sama.
Nějaké nápady jak toto řešit?
- Jan Suchánek
- Člen | 404
A co zkusit malsup.form.upload.js
Uprav řádky:
257: jqxhr = $.nette.ajax(options);
346: return $.nette.ajax(s);
a budeš si moci zprovznit fileupload i s porgress barem.
Ukázky s progress barem jsou zde
No a pak můžeš napsat extension pro nette.ajax.js
Editoval jenicek (4. 4. 2014 16:43)
- tobice
- Člen | 30
Úplně si nejsem jistý, jestli toto řeší můj problém. Jaký použiji plugin je mi celkem jedno, jde o tu implementaci na straně serveru, kdy potřebuji z vnitřku komponenty odpovědět nějakým JSONem či řetězcem. Kdybych řešil upload na úrovni presenteru, tak mohu udělat něco jako toto:
if ($this->isAjax()) {
$this->payload->message = 'Success';
}
Nicméně já řeším upload na úrovni komponenty, kde nemám jak ovlivnit odeslanou response, samozřejmě kromě samotného vykreslení komponenty. V podstatě se snažím vytvořit komunikační kanál mezi klientem a komponentou, jen mi v cestě stojí presenter.
- Mariocz
- Člen | 52
Možná blbost, nemam s tim zkušenosti ale presenter máš v Control k dispozici
$this->presenter;
- Jan Suchánek
- Člen | 404
@tobice: Upload mám jako komponentu po nahrátí souboru díky nette.ajax mi vrací snippet s nahranými soubory a proto nemusím řešit žádný jiný response.
Editoval jenicek (4. 4. 2014 17:36)
- tobice
- Člen | 30
jenicek napsal(a):
@tobice: Upload mám jako komponentu po nahrátí souboru díky nette.ajax mi vrací snippet s nahranými soubory a proto nemusím řešit žádný jiný response.
@jenicek: Jasně no, to je také řešení, v tomto případě i dobře aplikovatelné, obecně ale úplně ne. Abych to zobecnil, přidám další příklad. Řekněme, že mám komponentu diskuze pod článkem a chci umožnit jednoduché „lajkování“ příspěvků. Standardní přístup je ten, že prostě při „lajknutí“ invaliduji celý snippet obsahující danou komponentu, tím ale dojde k překreslení značné části stránky a celé to jaksi ztrácí na smyslu. Mnohem logičtější by bylo prostě jen serverem vrátit prázdnou odpověď s 200 v případě úspěchu či 40x/50× s chybovou hláškou.
@Mariocz: To zní dobře. Metoda
sendResponse()
je public
, tj. mohu v podstatě
odkudkoliv zastavit činnost presenteru a poslat prohlížeči, co potřebuji.
Jen to trochu nabourává moji představu uzavřené nezávislé
komponenty, nicméně vzhledem k tomu, že komponenta bez presenteru stejně
existovat nemůže, tak to asi žádné zlo není.
- Jiří Nápravník
- Člen | 710
Já standardně posílám odpovědi na ajax v komponentach pres $this->presenter→ a pak sendPayload vetsinou .
Jak uvádíš příklad s tím liknutím jendoho komentáře. Nemuší přece překreslovat celý formulář, ale dáš redrwarcontrol jen na ten daný komentář a pak se ti vrátí jen snippet toho jendoho komentáře…
- tobice
- Člen | 30
Jiří Nápravník napsal(a):
Já standardně posílám odpovědi na ajax v komponentach pres $this->presenter→ a pak sendPayload vetsinou .
Jak uvádíš příklad s tím liknutím jendoho komentáře. Nemuší přece překreslovat celý formulář, ale dáš redrwarcontrol jen na ten daný komentář a pak se ti vrátí jen snippet toho jendoho komentáře…
To je taky fakt.
Jinak já jsem to nakonec vyřešil přes Request
a
Response
, které si injectnu do komponenty. Vypadá to
nějak takto:
public function onError(Form $form)
{
if ($this->presenter->isAjax()) {
$this->httpResponse->setCode(Response::S400_BAD_REQUEST);
$response = new JsonResponse($form->getErrors());
$response->send($this->httpRequest, $this->httpResponse);
exit;
}
}
- Vojtěch Dobeš
- Gold Partner | 1316
To jsou prasárny :). Pro libovolné IResponse
by se vždycky
mělo použít volání Presenter::sendResponse()
. Takže
v komponentě:
$this->presenter->sendResponse(new JsonResponse($form->getErrors()));
Presenter bude v okamžiku zpracovávání formuláře určitě k dispozici.
exit()
není potřeba.
- tobice
- Člen | 30
vojtech.dobes napsal(a):
To jsou prasárny :). Pro libovolné
IResponse
by se vždycky mělo použít voláníPresenter::sendResponse()
. Takže v komponentě:$this->presenter->sendResponse(new JsonResponse($form->getErrors()));
Presenter bude v okamžiku zpracovávání formuláře určitě k dispozici.
exit()
není potřeba.
A jak tam dodám požadovaný HTTP status kód?
- tobice
- Člen | 30
Aha ona to nakonec není žádná věda :)
$this->httpResponse->setCode(Response::S400_BAD_REQUEST);
$this->presenter->sendResponse(new JsonResponse($data));
Každopádně je to drobátko matoucí. Poslat data můžu sice rovnou
pomocí sendResponse()
, ale pokud chci změnit stavový kód, tak
to musím udělat pomocí injectnuté Http\Response
(což
v případě komponenty není úplně triviální). Jinými slovy, když už
v presenteru to sendResponse()
je, tak bych čekal i možnost
změnit stavový kód, ale protože jsem tam tu možnost nenašel (že by tam
byla někde schovaná?), tak jsem usoudil, že bude lepší se zcela bez
presenteru obejít, a řešil jsem to přes
$response->send()
.