Přejít k navigační liště

Zdroják » JavaScript » Nette Framework: AJAX (pokračování)

Nette Framework: AJAX (pokračování)

Články JavaScript, PHP, Různé

Po seznámení se základy používání AJAXu v rámci frameworku Nette nastal čas podívat se na tvorbu interaktivních AJAXových aplikací do větší hloubky. Naučíme se pořádně pracovat s odpovědí serveru. A vyzkoušíme si tvorbu jednoduchého našeptávače.

předchozí části seriálu o Nette Framework jsme nakousli téma fragmentů HTML, označovaných ve frameworku jako snippety. Jde o bloky, které kodér označí v HTML šabloně párovou značkou {snippet}…{/snippet} a framework se už sám postará o to, aby při AJAXovém požadavku přenášel jen jejich obsah. Je poté na javascriptovém handleru, aby obsah snippetů vložil do aktuální stránky.

Protože snippetů může být ve stránce více, je možné je pojmenovat. Takto například vytvoříme snippet s názvem  counter:

{snippet counter}
Počet hlasů: {$count}
{/snippet} 

Pozn.: pokud by to prospělo přehlednosti, je možné název vložit i do koncové značky.

Při běžném, tj. neAJAXovém, požadavku vygeneruje šablona tento HTML kód:

<div id="__counter">Počet hlasů: 23</div> 

Jak vidíte, snippety se obalí do elementu div, jehož id tvoří název snippetu doplněný o dvě podtržítka. To aby se minimalizovala kolize s jinými id ve stránce.

Pokud byste chtěli div nahradit za jiný element, je možné jej specifikovat jako druhý parametr za názvem:

{snippet counter p}
Počet hlasů: {$count}
{/snippet} 

Vygeneruje:

<p id="__counter">Počet hlasů: 23</p> 

Toliko k běžnému požadavku. Nyní se naopak podívejme, jaká data se přenášejí při AJAXovém požadavku:

{"snippets":{"__counter":"Počet hlasů: 23"}} 

Výstupem je datová struktura, označovaná jako payload, serializovaná do JSON řetězce. V tomto případě server vrátil asociativní pole (v řeči JavaScriptu je přesnější termín objekt) s jedním prvkem snippets obsahujícím pole všech přenášených snippetů uložených jako pár ID a HTML kód.

Aktualizaci HTML stránky lze pak provést například tímto skriptem, který předpokládá přítomnost frameworku jQuery a proměnné  payload:

for (var id in payload.snippets) {
        $("#" + id).html(payload.snippets[id]);
} 

Které snippety přenášet?

Šablona může obsahovat spoustu snippetů. Jelikož Nette Framework je komponentově orientovaný, mohou se na stránce nacházet komponenty, jejichž šablony také obsahují snippety (přičemž samotný presenter není nic jiného, než speciální komponenta). Aby se při každém požadavku nepřenášely úplně všechny snippety, existuje ve frameworku mechanismus, jak určit, které přenést a které naopak vynechat. V řeči frameworku jde o odlišení neplatných a platných snippetů (neplatné se přenášejí). Ke zneplatnění slouží metoda invalidateCon­trol(), jejíž volitelný parameter je název snippetu. Pokud parametr neuvedeme, znamená to, že se zneplatní celá komponenta a tedy všechny snippety. Obdobně pro validaci existuje metoda validateControl().

Příklad použití:

public function renderDefault()
{
        $this->template->count = 23;
        $this->invalidateControl('counter'); // snippet 'counter' se přenese
} 

Nejen snippety živ je AJAX

Hned z kraje musím zmínit, že snippety představují jen vysokoúrovňový mechanismus, který vůbec nemusíte používat. To znamená, že můžete na výstup poslat jakýkoliv řetězec, ať už je to obyčejný HTML kód nebo serializovaná datová struktura. Přičemž pro datové struktury Nette Framework nabízí speciální podporu. Podívejme se na ni blíže.

Součástí presenteru je datové úložiště $presenter->payload (pozn. ve starších verzích frameworku bylo dostupné metodou getAjaxDriver()). Do tohoto úložiště můžete zapisovat jakákoliv data a presenter je nakonec pošle na výstup serializované, standardně jako JSON.

public function renderDefault()
{
        $this->payload->count = 23;
        $this->payload->show = TRUE;
        $this->terminate(); // ukončí presenter
} 

Vygeneruje:

{"count":23,"show":true} 

Ano, přesně tohle úložiště využívají i snippety, zapisují svůj obsah do $presenter->payload->snippets[$id] = $html. Samozřejmě lze zároveň používat snippety i zapisování uživatelských dat do $this->payload. Framework odešle na výstup vše.

Našeptávač

Přikladem samostatného použití $presenter->payload může být velmi jednoduchý našeptávač:

class AutoCompletePresenter extends Presenter
{

        public function handleAutoComplete($text)
        {
                $this->payload->autoComplete = array();

                $text = trim($text);
                if ($text !== '') {
                        // načteme seznam států (pro jednoduchost ze souboru)
                        $list = file(dirname(__FILE__) . '/items.txt');

                        // vytvoříme seznam pro našeptávač
                        foreach ($list as $item) {
                                $item = trim($item);
                                if (strncasecmp($item, $text, strlen($text)) === 0) {
                                        $this->payload->autoComplete[] = $item;
                                }
                        }
                }

                // činnost presenteru tímto můžeme ukončit
                $this->terminate();
        }

        ....
} 

V šabloně bude textové políčko a na něj zavěsíme handler pro událost onkeyup. Ta zavolá výše uvedenou metodu pomocí {link autoComplete!} a předá ji obsah políčka v parametru text. Od serveru získá pole payload.autoComplete, ze kterého seznam.

<p>Název státu: <input type="text" id="text" /></p>

<script type="text/javascript">
<!--
      $('#text').focus().keyup(function(event) {
            $.getJSON({link autoComplete!}, {'text': $('#text').val()}, function(payload) {
                        $('ul').remove();

                        var list = $('<ul></ul>').insertAfter('#text');

                        for (var i in payload.autoComplete) {
                              $('<li></li>').text(payload.autoComplete[i]).appendTo(list);
                        }
            });
      });
-->
</script> 
Zdrojový kód našeptávače vytvořeného výše je k dispozici ke stažení.

Pokračování příště

Tím jsme s AJAXem ještě úplně neskončili. Bude mu věnovaný i příští díl.


Autor článku je vývojář na volné noze, specializuje se na návrh a programování moderních webových aplikací. Pravidelně pořádá školení pro tvůrce webových aplikací, vyvíjí open-source knihovny Texy, dibi a Nette Framework.

Komentáře

Subscribe
Upozornit na
guest
12 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
honza

Čekal jsem, že tenhle seriál bude dobrý, ale tohle předčilo očekávání!

PACi

koukam, ze vyvoj frameworku jde vzdy ruku v ruce se serialem na rootu, kdyz jsem rozbalil aplikaci na serveru, tak nejela… a ono vcera vyslo nove nette… :-)

rokerkony

přesně tak :-) novinkou je metoda $presenter->getPayload()

http://forum.nettephp.com/cs/1649-prejmenovat-getajaxdriver?pid=10155

super článek :-)

Borek Bernard

"Invalidní = musí se přenášet" je asi první vtip ve frameworku, který jsem kdy viděl :) +1

aprilchild

jak moc (nebo nijak:) je s Nette svazano jQuery. Rekneme, ze bych ho chtel nahradit Mootools, protoze se mi ho nechce pouzivat?

Jarda

Vůbec není na jquery ani na jiný JS Framework vázané. Je to Vaše volba.

Jakub Vrána

Chápu, že to v kódu není uvedeno kvůli přehlednosti, ale neodpustím si poznámku, že JavaScriptová obsluha by měla respektovat asynchronnost AJAXu. Jde o to, že než mi připluje odpověď ze serveru, může se hodnota v políčku změnit.

Kromě této chyby by se dal kód samozřejmě dále vylepšit třeba tak, aby server nebombardoval požadavky častěji než je nutné, ale to už je skutečně nad rámec tohoto článku.

m3

nechci stourat, ale vyraz invalidni neni totez co v angl. invalidate. Zni to jako neco co neni validni a ne jako neco cemu skoncila platnost (z duvodu aktualizace dat), lepsi mi prijde napr. zneplatneny (odvozene od zrusit platnost – invalidate)

Borek Bernard

Tohle by možná ještě chtělo rozmyslet. Je pravda, že slovo invalidace se v tomto kontextu používá (např. Flex má interface IInvalidating [1]), nevýhodou ale je, že opakem je termín "validace", který se používá v úplně jiném významu. Například tvoje validateControl() ve mně evokuje běžnou validaci, nic s AJAXem.

Otázka je, co místo toho. Napadlo mě třeba markForRefresh(), forceRefresh() nebo setDirty(), ale určitě by se dalo přijít i na něco lepšího.

[1] http://livedocs.adobe.com/flex/3/langref/mx/core/IInvalidating.html

P.S. Ale stejně, "ivalidní, musí se tedy přenášet" se mi moc líbilo :)

manas

Ahoj,

nepochopil jsem vyznam $this->terminate() – v tomto pripade je script ukoncen a server odpovi s prazdnymi daty. Dokud jsem dany radek nezakomentoval, tak se nezobrazovaly vysledky naseptavace.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.