AJAX & snippety
Moderní webové aplikace dnes běží napůl na serveru, napůl v prohlížeči. AJAX je tím klíčovým spojovacím prvkem. Jakou podporu nabízí Nette Framework?
- posílání výřezů šablony (tzv. snippety)
- předávání proměnných mezi PHP a JavaScriptem
- debugování AJAXových aplikací
AJAXový požadavek lze detekovat metodou služby zapouzdřující
HTTP požadavek $httpRequest->isAjax() (detekuje podle HTTP
hlavičky X-Requested-With). Uvnitř presenteru je k dispozici
„zkratka“ v podobě metody $this->isAjax().
AJAXový požadavek se nijak neliší od klasického požadavku – je zavolán presenter s určitým view a parametry. Je také věcí presenteru, jak bude na něj reagovat: může použít vlastní rutinu, která vrátí nějaký fragment HTML kódu (HTML snippet), XML dokument, JSON objekt nebo kód v JavaScriptu.
Pro odesílání dat prohlížeči ve formátu JSON lze využít
předpřipravený objekt payload:
public function actionDelete($id)
{
if ($this->isAjax()) {
$this->payload->message = 'Success';
}
...
}
Pokud potřebujete plnou kontrolu nad odeslaným JSONem, použijte v presenteru JsonResponse. Tím ihned ukončíte činnost presenteru a obejdete se i bez šablony:
$this->sendResponse(new JsonResponse(array('klic' => 'hodnota', ...)));
Když chceme odeslat HTML, můžeme jednak zvolit speciální šablonu pro AJAX:
public function handleClick($param)
{
if ($this->isAjax()) {
$this->template->setFile('path/to/ajax.latte');
}
...
}
Nicméně daleko silnější nástroj představuje vestavěná podpora AJAXových snippetů. Díky ní lze udělat z obyčejné aplikace AJAXovou prakticky několika řádky kódu. Jak to celé funguje demonstruje příklad Fifteen, jehož kód najdete v distribuci.
Snippety fungují tak, že při prvotním (tedy neAJAXovém) požadavku se
přenese celá stránka a poté se při každém již AJAXovém subrequestu (=
požadavku na stejný presenter a view) přenáší pouze kód změněných
částí ve zmíněném úložišti payload. K tomu slouží dva
mechanismy: invalidace a renderování snippetů.
Invalidace
Každý objekt třídy Control (což je
i samotný Presenter) si umí zapamatovat, jestli při subrequestu došlo ke
změnám, které si vyžadují jej překreslit. K tomu slouží triptych metod
invalidateControl(), validateControl() a
isControlInvalid(). Příklad:
public function handleLogin($user)
{
// po přihlášení uživatele se musí objekt překreslit
$this->invalidateControl();
...
}
Nette však nabízí ještě jemnější rozlišení, než na úrovni komponent. Uvedené metody mohou totiž jako parametr nabývat název tzv. „snippetu“, nebo-li výstřižku. Lze tedy invalidovat (rozuměj: vynutit překreslení) na úrovni těchto snippetů (každý objekt může mít libovolné množství snippetů). Pokud se invaliduje celá komponenta, tak se i každý snippet překreslí. Komponenta je „invalidní“ i tehdy, pokud je invalidní některá její subkomponenta.
echo $this->isControlInvalid(); // -> FALSE
$this->invalidateControl('header'); // invaliduje snippet 'header'
echo $this->isControlInvalid('header'); // -> TRUE
echo $this->isControlInvalid('footer'); // -> FALSE
echo $this->isControlInvalid(); // -> TRUE, alespoň jeden snippet je invalid
$this->invalidateControl(); // invaliduje celou komponentu, každý snippet
echo $this->isControlInvalid('footer'); // -> TRUE
Komponenta, která přijímá signál, je automaticky označena za invalidní.
Díky invalidaci snippetů přesně víme, které části kterých prvků bude potřeba překreslit.
Makro {snippet} … {/snippet}
Nette je založeno na myšlence logických, nikoliv grafických prvků, tj. objekt třídy Control nepředstavuje pravoúhlou oblast ve stránce, ale logickou komponentu, která se může renderovat i do více podob (např. hypotetická komponenta DataGrid může mít jednu metodu pro vykreslení mřížky a druhou pro vykreslení „stránkovadla“ apod). Každý prvek může být navíc na stránce vykreslen vícekrát, nebo podmíněně, nebo pokaždé s jinou šablonou atd.
Není tedy možné jednoduše zavolat nějakou metodu render na
každém invalidním objektu. K vykreslování je nutné přistupovat tak, jako
když se kreslí celá stránka. Vykreslování stránky probíhá velmi
podobně, jako u neAJAXového požadavku, načtou se tytéž šablony atd.
Klíčovým úkolem však je vypustit ty části, které se na výstup vůbec
dostat nemají, a ty, které se vykreslit mají, přidružit s identifikátorem
a poslat klientovi ve formátu, kterému bude obslužný JavaScript
rozumět.
Pokud se uvnitř šablony nachází control nebo snippet, musíme jej obalit
párovou značkou {snippet} ... {/snippet} – ty totiž zajistí,
že se vykreslený snippet vystřihne a pošle do prohlížeče. Také jej
obalí pomocnou značkou <div> (lze použít i jinou
značku). V uvedeném příkladě je snippet pojmenován jako
header a může představovat i například šablonu controlu:
{snippet header}
<h1>Hello .... </h1>
{/snippet}
Debuggování AJAXových aplikací
TODO
Komentáře 
knyttl | 29. 9. 2011, 0:15 | comment
Mělo by se doplnit, že například pomocí {snippet titleSnippet
title}{include #title}{/title} lze pěkně měnit ajaxovou hlavičku
titulek.
pilec | 1. 2. 2012, 12:35 | comment
O AJAXu se taky pěkně rozpovídal Vojtěch Dobeš na této přednášce


ondra310 | 26. 7. 2011, 15:03 | comment
Dovolil bych si upozornit nove prichozi na nefunkcnost snipetu v includovanych sablonach. Viz tema: http://forum.nette.org/…vana-sablona. Stalo me to docela dost casu nez jsem prisel na to, ze to takhle nejde. Z ukazkoveho prikladu neni duvod predpokladat, ze by snipety nemuseli fungovat v include sablonach.