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

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.

Seriál: Začínáme s Nette Framework (17 dílů)

  1. Nette Framework: zvyšte svoji produktivitu 10.3.2009
  2. Nette Framework: Odvšivujeme 17.3.2009
  3. Nette Framework: MVC & MVP 24.3.2009
  4. Nette Framework: Refactoring 31.3.2009
  5. Nette Framework: Chytré šablony 7.4.2009
  6. Nette Framework: adresářová struktura aplikace 14.4.2009
  7. Nette Framework: AJAX 21.4.2009
  8. Nette Framework: AJAX (pokračování) 28.4.2009
  9. Nette Framework: AJAX (dokončení) 5.5.2009
  10. Nette Framework: Sessions 12.5.2009
  11. Nette Framework: Přihlašování uživatelů 19.5.2009
  12. Nette Framework: Ověřování oprávnění a role 26.5.2009
  13. Nette Framework: Neprůstřelné formuláře 2.6.2009
  14. Nette Framework: Neprůstřelné formuláře II 9.6.2009
  15. Nette Framework: Neprůstřelné formuláře III 16.6.2009
  16. Nette Framework: Cache 23.6.2009
  17. Nette Framework: Co se do seriálu nevešlo? 30.6.2009

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.

David Grudl školí, je autorem PHP knihoven Nette Framework, databázové vrstvy dibi a formátovače HTML kódu Texy!.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 12

Přehled komentářů

honza to je cool!
PACi vyvoj frameworku
rokerkony Re: vyvoj frameworku
Borek Bernard Invalidní snippet
aprilchild mootools
Jarda Re: mootools
Jakub Vrána Asynchronost AJAX
m3 invalidate
David Grudl Re: invalidate
Borek Bernard Re: invalidate
David Grudl Re: invalidate
manas Proc $this->terminate() ?
Zdroj: https://www.zdrojak.cz/?p=2999