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

Zdroják » JavaScript » Nette Framework: AJAX

Nette Framework: AJAX

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

AJAXové aplikace jsou populární, neboť poskytují uživatelsky příjemnější prostředí. Pro programátory je však AJAX často noční můrou (nemluvě o tom, že špatná AJAXová aplikace je noční můrou pro uživatele). V následujících dílech se proto podíváme, jak správně psát AJAXové aplikace za použití Nette Framework.

Aby nedošlo k nedorozuměním, definujme si nejdřív, co je to vlastně AJAX je. Jde o skupinu technologií sloužících k vytváření interaktivních webových aplikací, které mohou komunikovat se serverem bez nutnosti znovunačtení stránky. Navzdory názvu Asynchronous JavaScript and XML se nevyžaduje ani JavaScript, ani XML, ani asynchronnost.

Zatímco samotná komunikace se serverem nepředstavuje zásadnější problém, objevují se jiné komplikace:

  • jak reprezentovat aktuální stav aplikace v adresním řádku
  • jak reagovat na tlačítka Zpět, Vpřed a pohyb v historii navštívených stránek
  • jak se vyhnout závislosti na JavaScriptu
  • jak uživateli signalizovat, že aplikace zpracovává jeho požadavek
  • udržet pod kontrolou zátěž serveru; AJAX může snížit zátěž na webové servery, ale může zvýšit počet HTTP požadavků

Zatímco pro některé úkoly již existují zavedené návrhové vzory (zpracování se signalizuje známým animovaným GIFem, stav aplikace se zaznamenává do fragmentu webové adresy), pro jiné je třeba použít různé triky a hacky. Do této kategorie patří zejména odchytávání stisknutí tlačítek Zpět či Vpřed nebo procházení historií, kde s čistým řešením přichází teprve HTML5.

JavaScript a PHP hrají ping-pong

Rozdíl v programování klasické a AJAXové aplikace je v zapojení nové vrstvy napsané v JavaScriptu do hry. Zatímco v klasické aplikaci kliknutí na odkaz automaticky vyvolá požadavek na server a vrácená stránka se automaticky zobrazí, v případě AJAXových aplikací požadavek vyvolá a vrácená data zpracuje klientský skript. Nazývejme takový požadavek AJAXovým. Přičemž z pohledu webového serveru jde stále o normální GET nebo POST požadavek HTTP.

Jinými slovy:

  1. JavaScript zformuluje interakci uživatele do GET nebo POST požadavku a zašle na server
  2. PHP odpoví
  3. JavaScript dekóduje odpověď a provede reakci

JavaScript tak hraje s PHP ping-pong a má vždy výhodu podání. Kromě toho by měl zobrazovat a skrývat obrázek signalizující zpracování požadavku a může také aktualizovat stav uložený ve fragmentu webové adresy.

Nejprve se pod lupou podíváme na druhou fázi pohybu ping-pongového míčku – jak může vypadat odpověď serveru?

1) HTML stránka

AJAXovou aplikaci je dokonce možné postavit i nad serverem, který odmítá spolupráci. Stačí, že vrátí celou HTML stránku, a je to obslužný JavaScript, kdo z ní vytáhne potřebné informace (obvykle elementy HTML, které pak zapracuje do aktuální stránky v prohlížeči a zbytek zahodí). Přesně tohle dělá funkce load z frameworku jQuery.

2) HTML fragment

Předchozí postup je sice snadný, ale poměrně neefektivní. Server musí třeba vygenerovat složitou a objemnou stránku, ze které se použije jen zlomek a zbytek se zahodí. Vhodnější je proto dopsat na straně serveru podporu, která bude umět vrátit jen tu část stránky, která se změnila. Tedy jakýsi fragment HTML.

3) JSON nebo XML

Co kdyby došlo k více změnám na různých místech stránky? V takovém případě je potřeba předat fragmentů HTML víc. Například ve formě asociativního pole, kde klíče budou ID elementů a hodnoty jejich HTML kódy. Na to ovšem potřebujeme složitější struktury. Třeba JSON nebo XML.

ČTĚTE K TÉMATU: JSON pro výměnu dat na webu

Obojí jsou standardizované formáty pro výměnu dat. Oba se na straně JavaScriptu i PHP snadno čtou i generují (i když práce s JSON na straně JavaScriptu má svá úskalí). A nemusí sloužit pouze k předání HTML fragmentů, lze jít dál a zcela opustit vrstvu HTML. Je možné předávat data, ze kterých teprve samotný JavaScript vygeneruje HTML kód nebo bude manipulovat s aktuální stránkou.

4) Žádný obsah

Aby byl výčet kompletní, je třeba uvést i situaci, kdy server žádný obsah nepošle. Znáte ty hlasovací otázky Líbil se vám článek? na blozích? Pomocí AJAXu zaznamenávají kliknutí, server inkrementuje čítač v databázové tabulce, ale už nemá co odpovědět.

Zajímavostí je, že tento typ AJAXového požadavku lze realizovat dokonce bez klientského skriptování. Stačí obyčejný hypertextový odkaz, na který server odpoví HTTP kódem 204 No Content. Podle specifikace poté nesmí prohlížeč znovunačíst stránku, což také browsery dodržují.

Nicméně i v tomto případě je záhodno připojit klientský skript, který odkaz nahradí např. oznámením Váš hlas byl zaznamenán. Jinak bude uživatel zmaten a bude opakovaně klikat na odkaz s očekáváním nějaké reakce.

AJAX a Nette Framework

Nette Framework podporuje všechny ping-pongové míčky, tedy všechny typy komunikace. Nenutí vás používat žádnou konkrétní javascriptovou knihovnu, takže si můžete napsat vlastní obslužný skript, můžete využít jQuery atd. Framework podporuje a velmi zjednodušuje zasílání fragmentů HTML. A vede programátora k tvorbě aplikací, které plně fungují i bez JavaScriptu.

Možná budete až překvapeni, jak snadno naučíme Automat na kávu AJAX.

Navrhoval bych využít javascriptový framework jQuery. Můžete samozřejmě namítnout, že k obsluze jednoduchého AJAXového požadavku je zbytečné natahovat celý framework, a budete mít pravdu. Jenže v praxi obvykle u samotné komunikace se serverem nezůstane, je potřeba provádět různé kejkle s dokumentem a bavit uživatele vizuálními efekty, ke kterým framework už potřeba je. S tímto vědomím ho použijeme i nyní. A společně s ním i Nette Framework plugin pro jQuery, jehož autorem je Jan Marek.

Plugin obslouží zbývající dvě fáze ping-pongové hry. Tou první je odeslání reakce uživatele na server prostřednictví AJAXového požadavku. Slovy kodéra to znamená zavěsit na kotvy <a href="..."> obsluhu události onclick, která operace vykoná a vrátí false, aby prohlížeč nenačetl další stránku.

<a href="{link insert!, 1}" onclick="obsluznyHandler(); return false">
  <img src="images/coin-1.png" alt="Vhoď 1 Kč" />
</a> 

Existuje však elegantnější způsob, známý jako unobtrusive JavaScript. Spočívá v tom, že obsluhu událostí zavěsíme pomocí skriptu. Například na všechny kotvy, které mají třídu ajax. Takže v šablonách bude jen:

<a href="{link insert!, 1}" class="ajax">
  <img src="images/coin-1.png" alt="Vhoď 1 Kč" />
</a> 

A následující kód, který najdete v souboru jquery.nette.js, všechny kotvy „zAJAXovatí“.

$(function() {
        // nastaví událost onclick pro všechny elementy A s třídou 'ajax'
        $("a.ajax").live("click", function(event) {
                $.get(this.href); // zahájí AJAXový požadavek

                // zobrazí spinner, signalizující uživateli, že se něco děje
                $('<div id="ajax-spinner"></div>').css({
                        position: "absolute",
                        left: event.pageX + 20,
                        top: event.pageY + 40

                }).ajaxStop(function() {
                        $(this).remove(); // po skončení spinner smaž

                }).appendTo("body");

                return false;
        });
}); 

Třetí a poslední fází ping-pongu je zpracování odpovědi vrácené serverem. Skript jquery.nette.js tím pověří handler  jQuery.netteCallback:

jQuery.extend({
        updateSnippet: function(id, html) {
                $("#" + id).html(html);
        },

        netteCallback: function(data) {
                // přesměrování
                if (data.redirect) {
                        window.location.href = data.redirect;
                }

                // snippety
                if (data.snippets) {
                        for (var i in data.snippets) {
                                jQuery.updateSnippet(i, data.snippets[i]);
                        }
                }
        }
});


jQuery.ajaxSetup({
        success: function (data) {
                jQuery.netteCallback(data);
        },

        dataType: "json"
}); 

Handler očekává JSON strukturu, která obsahuje buď příkaz pro přesměrování, nebo pole fragmentů HTML (ve frameworku nazývaných snippety), které vloží na příslušná místa aktuální stránky.

Plugin jquery.nette.js je univerzální a můžete ho použít v jakékoliv Nette aplikaci, nejen v Automatu na kávu. Samozřejmě ho musíme zalinkovat v šabloně @layout.phtml a doplnit CSS styl pro  ajax-spinner.

<script src="js/jquery.js" type="text/javascript"></script>
<script src="js/jquery.nette.js" type="text/javascript"></script> 

Na straně JavaScriptu máme hotovo, pojďme se podívat na stranu PHP aplikace. Naučit presenter odpovídat na AJAXové požadavky bude velmi jednoduché. Vlastně stačí jediné – označít v šabloně fragmenty HTML, tedy místa, které se mají přenášet. K tomu slouží párová značka {snippet}...{/snippet}. O zbytek už se postará framework.

<body>
        {snippet}
        {include $content}
        {/snippet}
</body> 

Pravda, je tu ještě jedna věc – ve třetí části seriálu jsme si říkali, že po vykonání příkazu by mělo následovat přesměrování na další stránku a následně jsme do metody MachinePresenter::handleInsert() takové přesměrování přidali. V AJAXu ale přesměrovat nechceme, takže volání metody redirect podmíníme otázkou, zda je aktuální požadavek AJAXový. K čemuž slouží metoda  isAjax().

Soubor MachinePresenter.php:

public function handleInsert($coin)
{
        // zvýšíme hodnotu vhozených mincí
        $this->money += max(0, (int) $coin);

        // po příkazu musí následovat přesměrování, ale ne v AJAXu
        if (!$this->isAjax()) {
                $this->redirect('this');
        }
} 

A to je vše! Ano, právě jsme naučili automat na kávu AJAX. AJAXnadno! Přičemž automat je stále plně funkční i pro uživatele bez JavaScriptu.

Zdrojový kód diskutovaný v článku je k dispozici ke stažení.

Celá problematika AJAXu je mnohem zajímavější a rozmanitější, takže v příštím díle se podíváme na HTML fragmenty podrobněji a ukážeme si další formy komunikace.


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.

Používáte AJAX?

Komentáře

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

Nesmrdí ten snippet v šabloně špatným návrhem? Nejsem pomlouvačná šlapka, jen přemýšlím co by se dělo kdyby tam těch snippetů bylo víc…

MazeGen

Co má být ten "Automat na kávu"?

rokerkony

stačí si přečíst předchozí články :-)
viz: http://zdrojak.root.cz/clanky/nette-framework-mvc–mvp/

Golf

Nette pracuje s Ajaxem jednoduše a přitom geniálně. Něco takového jsem dlouho hledal, ale když to už konečně přišlo, je pro mne trochu pozdě, neboť jsem se rozhodl JS vyměnit za AS. Zabývám se myšlenkou, co kdyby pinpongovým míčkem nebylo XML, nebo JSON ale AMF a místo javascriptu by byl na straně clienta Adobe Flex. Zkoušel jsem na straně serveru použít Symfony (používá externí AMF parser jako plugin), Zend (má vlastní AMF parser) a Nette (AMF parser nemá, ale není problém použít třeba Zend_Amf, nebo něco jiného podle chuti).

Nakonec jsem se pro výše uvedené řešení rozhodl použít Nette (například proto, protože je ze všech tří kandidátů nejštíhlejší), byť se musí trochu přiohnout (např. vytvořit si funkci isAmf()). Ve flex-PHP(Nette) aplikaci jsou náhle trochu na obtíž všechny ty užasné věci orientované na view, ale routing, configurace, caching, nebo třeba i authorizace pořád dobře poslouží. Jsem zatím na začátku této cesty a uvítal bych diskusi na toto téma, pokud máte někdo nějaké zkušenosti.

Martin Malý

(Nechce se mi hledat login name) Nevěřím očím, ty, Flexobijec, se náhle s takovou technologií brtříčkuješ…? Znamená to snad posun názoru na Flex, nebo ses rozhodl být prgmatik? :)

Dundee5

Velmi pěkná ukázka Davide, díky!

petiar

musím pochváliť autora za skvele napísaný seriál, vážne sa to dobre číta. špeciálne uznanie za slovnú hračku AJAXnadno!

trantaloid

to je pekne :))

mival1234

Dobrý den,
velmi se mi líbí tento tutoriál o Nette, ale měl bych dotaz. Uvažujete někdy o přepracování (upravení) textu, tak aby byl funkční i ve verzi 1? Po delší době zkoušení se mi podařilo zprovoznit layouty ale AJAX požadavky nefungují. Problikne gif signalizující AJAX požadavek, ale nezmění se stav vhozených mincí. Předem děkuji za odpověď

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.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.