Jak z komponenty na AJAXový request odpovědět pouze řetězcem či jsonem

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

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

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

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

Možná blbost, nemam s tim zkušenosti ale presenter máš v Control k dispozici

$this->presenter;

https://api.nette.org/…mponent.html#…

Jan Suchánek
Člen | 404
+
0
-

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

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

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

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

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

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

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().