Rozdział 7. Ajax

> Dodaj do ulubionych

Wprowadzenie do technologii Ajax

Obiekt XMLHttpRequest (XHR) umożliwia komunikację przeglądarki z serwerem bez przeładowywania całej strony. Dzięki tej technice, znanej również jako Ajax (Asynchronous JavaScript and XML) można wzbogacić stronę o interaktywne elementy.

Żądania Ajax są wyzwalane przez kod JavaScript — polega to na wysłaniu żądania pod określony adres URL, w wyniku czego otrzymuje się odpowiedź, która może zostać obsłużona przez wywołanie zwrotne. Żądania mają charakter asynchroniczny, co oznacza, że pozostała część kodu jest wykonywana w trakcie ich przetwarzania. Do obsługi odpowiedzi musi więc zostać użyte wywołanie zwrotne.

W bibliotece jQuery znajdziemy opracowane pod kątem Ajaksa rozwiązania, które pozwalają na prawidłowe wykonanie kodu w każdej przeglądarce. Do dyspozycji mamy rozbudowaną metodę $.ajax(), a także proste metody pomocnicze, np. $.get(), $.getScript(), $.getJSON(), $.post() i $().load().

Choć nazwa Ajax może sugerować co innego, większość aplikacji wykorzystujących tę technikę i napisanych z wykorzystaniem biblioteki jQuery nie korzysta z formatu XML. Zamiast tego dane przesyłane są w postaci czystego kodu HTML lub w formacie JSON.

Z reguły z Ajaksa można korzystać tylko w obrębie domeny, na której umieszczony jest serwis. Wyjątek stanowią serwisy obsługujące JSONP, który pozwala na ograniczony dostęp Ajaksa do innych domen.

Podstawowe pojęcia Ajaksa

Aby odpowiednio korzystać ze związanych z Ajaksem metod jQuery, należy zrozumieć kilka podstawowych pojęć.

GET a POST

Dwie najpopularniejsze metody wysyłania żądań do serwera to GET i POST. Należy dobrze zrozumieć, do czego każda z nich służy.

Metoda GET powinna być wykorzystana do operacji, które tylko pobierają dane z serwera, bez wprowadzania zmian. Żądaniem GET może być na przykład zapytanie wysłane do wyszukiwarki. Żądania GET mogą być przechowywane w pamięci podręcznej przeglądarki, co może spowodować nieprzewidywalne zachowanie kodu, jeśli się tego nie przewidzi w programie. Dane żądania GET przesyłane są zazwyczaj w postaci łańcucha zapytania.

W przypadku operacji, które zmieniają znajdujące się na serwerze dane powinno się korzystać z metody POST. Żądanie takie powinien wysyłać na przykład użytkownik zapisujący swój wpis na blogu. Z reguły żądania POST nie są przechowywane w pamięci podręcznej przeglądarki. Łańcuch zapytania może być częścią adresu URL, jednak dane żądania przeważnie wysyłane są osobno.

Typy danych

Zazwyczaj musimy przekazać bibliotece jQuery informacje na temat typu danych, jaki chcemy otrzymać w odpowiedzi na żądanie Ajax. W niektórych przypadkach typ danych określa nazwa metody, a czasem zawarty jest on w obiekcie konfiguracji. Oto kilka dostępnych opcji:

text
Dane w postaci prostych łańcuchów
html
Bloki kodu HTML, który ma zostać umieszczony na stronie
script
Służy do dodawania na stronę nowego skryptu
json

Dane w formacie JSON — mogą być to ciągi, tablice lub obiekty

jsonp
Do przesyłania danych w formacie JSON z innej domeny
xml
Do przesyłania danych w zdefiniowanym przez użytkownika schemacie XML

W większości przypadków jestem wielką zwolenniczką formatu JSON, ponieważ daje on największą elastyczność. Warto z niego skorzystać zwłaszcza jeśli chcemy wysłać kod HTML i dane jednocześnie.

A jak asynchroniczny

Asynchroniczność Ajaksa potrafi uśpić czujność wielu nowych użytkowników biblioteki jQuery. Ponieważ wywołania Ajaksa są domyślnie asynchroniczne, odpowiedź nie jest dostępna od razu i można ją obsłużyć tylko za pomocą wywołania zwrotnego. Poniższy kod zatem nie zadziała:

var odpowiedz;
	$.get('foo.php', function(o) { odpowiedz = o; });
	console.log(odpowiedz); // niezdefiniowane!

Należy natomiast przekazać do żądania funkcję wywołania zwrotnego. Zostanie ona wykonana jak tylko żądanie się powiedzie — jeśli zostały zwrócone jakieś dane, to wówczas uzyskamy do nich dostęp.

$.get('foo.php', function(odpowiedz) { console.log(odpowiedz); });

Zasada tożsamego pochodzenia i JSONP

Z reguły żądania Ajaksa mogą być wysyłane tylko w obrębie tego samego protokołu (HTTP lub HTTPS), tego samego portu i tej samej domeny, co strona wysyłająca żądanie. Ograniczenie to nie obowiązuje w przypadku skryptów ładowanych za pomocą związanych z Ajaksem metod jQuery.

Inny wyjątek stanowią żądania wysyłane do usług JSONP, umieszczonych w innej domenie. W przypadku JSONP usługodawca zgadza się odpowiedzieć na żądanie skryptem, który można umieścić na stronie za pomocą elementu script, co pozwala uniknąć ograniczeń płynących z zasady tożsamego pochodzenia. W skrypcie znajdują się żądane dane, opakowane w dostarczoną przez nas funkcję wywołania zwrotnego.

Ajax i Firebug

Firebug (lub Webkit Inspector w przeglądarce Chrome i Safari) to bezcenne narzędzia w pracy z żądaniami Ajax. Przetwarzane żądania Ajax widoczne są w Firebugu w zakładce Konsola (albo w zakładce Resources > XHR panel w Webkit Inspectorze). Można również kliknąć dowolne żądanie, aby zobaczyć jego szczegóły, np. nagłówki czy treść żądania, nagłówki odpowiedzi i inne. Jeśli w czasie przetwarzania żądania występują jakieś błędy, to właśnie tu w pierwszej kolejności należy szukać ich źródła.

Metody jQuery związane z Ajaksem

W bibliotece jQuery dostępnych jest wiele związanych z Ajaksem metod pomocniczych, jednak najważniejszą wśród nich rolę gra metoda $.ajax, dlatego bezwzględnie należy zrozumieć jej działanie. Zostanie ona omówiona w pierwszej kolejności, a następnie krótko opiszę metody pomocnicze.

Przeważnie korzystam tylko z metody $.ajax — jak sam zobaczysz, jej możliwości są znacznie większe od metod pomocniczych, a ponadto ma, moim zdaniem, bardziej zrozumiałą składnię.

Metoda $.ajax

Metoda jQuery $.ajax ma duże możliwości, a przy tym pozwala tworzyć żądania Ajax w prosty sposób. Przyjmuje ona obiekt konfiguracji zawierający wszystkie instrukcje, które są niezbędne dla jQuery do wykonania żądania. Co szczególnie istotne, metoda $.ajax pozwala określić wywołanie zwrotne, które ma zostać wykonane w przypadku żądania zakończonego powodzeniem jak i porażką. Ponadto możliwość przekazywania do niej niezależnie zdefiniowanego obiektu konfiguracji sprawia, że łatwiej jest pisać kod nadający się do wielokrotnego użytku. Pełną dokumentację dot. opcji konfiguracji można znaleźć na stronie http://api.jquery.com/jQuery.ajax/.

Przykład 7.1. Korzystanie z metody $.ajax

$.ajax({
	    // adres URL żądania
	    url : 'post.php',
	 
	    // dane, które mają zostać wysłane
	    // (zostaną przekształcone na łańcuch zapytania)
	    data : { id : 123 },
	 
	    // określamy typ żądania — POST lub GET
	    type : 'GET',
	 
	    // typ danych, jaki chcemy otrzymać
	    dataType : 'json',
	 
	    //kod, który ma zostać wykonany jeśli żądanie się powiedzie;
	    // odpowiedź jest przekazywana do funkcji
	    success : function(json) {
	        $('<h1/>').text(json.title).appendTo('body');
	        $('<div class="tresc"/>')
	            .html(json.html).appendTo('body');
	    },
	 
	    // kod, który ma zostać wykonany jeśli żądanie się nie powiedzie;
	    // nieprzetworzone żądanie oraz kody stanu są
	    // przekazywane do funkcji
	    error : function(xhr, status) {
	        alert('Przepraszamy, wystąpił problem!');
	    },
	 
	    // kod, który ma zostać wykonany bez względu na to, czy żądanie zostało zakończone powodzeniem, czy nie
	    complete : function(xhr, status) {
	        alert('Żądanie wykonane!');
	    }
	});

Parametry metody $.ajax

Metoda $.ajax przyjmuje wiele parametrów, które są jednym z czynników decydujących o jej przydatności. Pełen spis parametrów znajduje się na stronie http://api.jquery.com/jQuery.ajax/. Oto zaś kilka najczęściej używanych:

async
Jeśli żądanie ma zostać wysłane synchronicznie, należy ustawić wartość false. Warto zwrócić uwagę, że wówczas żądanie zablokuje wykonywanie pozostałego kodu do czasu otrzymania odpowiedzi. Domyślna wartość tego parametru to true.
cache
Parametr określający, czy ma zostać użyta odpowiedź zapisana w pamięci podręcznej (o ile jest dostępna). Domyślna wartość to true dla wszystkich typów danych z wyjątkiem formatu script i jsonp. W przypadku ustawienia wartości false, do adresu URL zostanie dołączony parametr blokujący użycie pamięci podręcznej.
complete
Funkcja wywołania zwrotnego, która ma zostać wykonana po przesłaniu żądania, bez względu na to, czy zostało zakończone powodzeniem. Funkcja otrzymuje nieprzetworzony obiekt żądania oraz status żądania w formie tekstowej.
context
Zakres, w którym mają być wykonywane funkcje wywołania zwrotnego (innymi słowy określamy, do czego będzie odwoływać się słowo this wewnątrz funkcji). Domyślnie this odwołuje się do obiektu, który został oryginalnie przekazany do metody $.ajax.
data
Dane, które mają być przesłane do serwera. Może być to obiekt lub łańcuch zapytania, np. foo=bar&baz=bim.
dataType
Typ danych, jaki chcesz otrzymać z serwera. Jeśli żaden typ nie zostanie określony, jQuery sprawdzi typ MIME odpowiedzi.
error
Funkcja wywołania zwrotnego, która ma zostać wywołana, jeśli podczas przesyłania żądania wystąpi błąd. Funkcja otrzymuje nieprzetworzony obiekt żądania oraz status żądania w formie tekstowej.
jsonp
Nazwa wywołania zwrotnego, które ma zostać przesłane w łańcuchu zapytania podczas żądania JSONP. Domyślne ustawienie to callback.
success
Funkcja wywołania zwrotnego, która ma zostać wykonana, jeśli żądanie powiedzie się. Funkcja przyjmuje dane odpowiedzi (przekonwertowane na obiekt JavaScript jeśli parametr dataType usatwiony był na JSON), a także status połączenia w formie tekstowej wraz z nieprzetworzonym obiektem żądania.
timeout
Mierzony w milisekundach czas, po upływie którego żądanie zostanie uznane za nieudane.
traditional
Wartość true ustawi serializację parametrów stosowaną w starszych wersjach jQuery niż 1.4. Szczegółowe informacje znajdziesz na stronie http://api.jquery.com/jQuery.param/.
type
Typ żądania — POST lub GET. Domyślna wartość parametru to GET. Istnieje możliwość ustawienia innych żądań, np. PUT lub DELETE, jednak mogą być one nieobsługiwane przez niektóre przeglądarki.
url
Adres URL żądania.

Jest to jedyny wymagany parametr obiektu konfiguracji metody $.ajax. Pozostałe własności są opcjonalne.

Metody pomocniczce

Jeśli nie potrzebujesz tak zaawansowanych ustawień konfiguracji, jakie dostępne są w metodzie $.ajax i nie przeszkadza ci samodzielna obsługa błędów, skorzystaj z dostępnych w jQuery funkcji pomocniczych Ajaksa — stanowią one zwięzłą alternatywę przydatną w pracy z żądaniami. Metody te „opakowują” podstawową metodę $.ajax i z góry ustawiają jej niektóre parametry.

Oto dostępne w bibliotece jQuery metody pomocnicze:

$.get
Wysyła żądanie GET pod podany adres URL.
$.post
Wysyła żądanie POST pod podany adres URL.
$.getScript
Dodaje na stronę skrypt.
$.getJSON
Wykonuje żądanie GET, w odpowiedzi na które mają zostać zwrócone dane JSON.

Każda z tych metod przyjmuje poniższe argumenty w następującej kolejności:

URL
Adres URL żądania. Wymagany.
dane
Dane, które mają być przesłane do serwera. Może być nimi obiekt lub łańcuch zapytania, np. foo=bar&baz=bim. Argument opcjonalny.

Uwaga: nie jest to prawidłowy argument metody $.getScript.

Wywołanie zwrotne powodzenia
Funkcja wywołania zwrotnego, która ma zostać wykonana, jeśli żądanie powiedzie się. Funkcja otrzymuje dane odpowiedzi (przekonwertowane na obiekt JavaScript, jeśli typ danych ustawiony był na JSON), a także nieprzetworzony obiekt żądania oraz status żądania w formie tekstowej. Argument opcjonalny.
typ danych
Typ danych, jaki chcemy otrzymać z serwera. Argument opcjonalny.

Przykład 7.2. Korzystanie ze związanych z Ajaksem metod pomocniczych jQuery

// pobierz czysty tekst lub kod HTML
	$.get('/uzytkownicy.php', { idUzytkownika : 1234 }, function(odp) {
	    console.log(odp);
	});
	 
	// dodaj na stronę skrypt, a następnie wykonaj zdefiniowaną w nim funkcję
	$.getScript('/static/js/mojSkrypt.js', function() {
	    funkcjaZMojegoSkryptu();
	});
	 
	// pobierz z serwera dane w formacie JSON
	$.getJSON('/szczegoly.php', function(odp) {
	    $.each(odp, function(k, w) {
	        console.log(k + ' : ' + w);
	    });
	});
$.fn.load

Metoda $.fn.load wyróżnia się na tle innych metod jQuery związanych z Ajaksem, ponieważ wywołuje się ją na zestawie wybranych elementów. Metoda ta pobiera z adresu URL kod HTML, którym następnie wypełnia wybrane elementy. Oprócz adresu URL możesz także opcjonalnie przekazać do niej selektor — jQuery pobierze wówczas tylko pasujące do niego fragmenty zwróconego kodu HTML.

Przykład 7.3. Korzystamy z metody $.fn.load do zapełnienia elementu

$('#nowaTresc').load('/foo.html');

Przykład 7.4. Korzystamy z metody $.fn.load do zapełnienia wybranego selektorem elementu

$('#nowaTresc').load('/foo.html #mojDiv h1:first', function(html) {
	  alert('Treść została zaktualizowana!');
	});

Ajax i formularze HTML

Korzystanie z technologii Ajax i biblioteki jQuery przydaje się zwłaszcza podczas pracy z formularzami. Wtyczka jQuery Form jest sprawdzonym narzędziem, za pomocą którego można dodać Ajax do formularzy. Do obsługi formularzy Ajax z reguły najlepiej wykorzystywać samą wtyczkę niż samemu szukać rozwiązań skomplikowanych problemów. Warte zapamiętania metody jQuery związane z przetwarzaniem formularzy to $.fn.serialize i $.fn.serializeArray.

Przykład 7.5. Przekształcamy dane formularza w łańcuch zapytania

$('#mojFormularz').serialize();

Przykład 7.6. Tworzymy tablicę obiektów zawierającą dane z formularza

$('#mojFormularz').serializeArray();
	 
	// utworzy taką strukturę:
	[
	    { nazwa : 'pole1', wartosc : 123 },
	    { nazwa : 'pole2', wartosc : 'witaj, świecie' }
	]

Praca z formatem JSONP

Pojawienie się formatu JSONP — umożliwiającego przechwycenie skryptu w sposób akceptowany przez właściciela serwisu — pozwoliło na kombinacje treści stron. Wiele dużych stron internetowych oferuje serwisy JSONP, dzięki czemu użytkownik może uzyskać dostęp do ich treści za pomocą predefiniowanego API. Godnym odnotowania źródłem danych w formacie JSONP jest serwis Yahoo! Query Language, który w poniższym przykładzie wykorzystamy do pobrania informacji na temat kotów.

Przykład 7.7. Korzystanie z serwisu YQL i danych w formacie JSONP

$.ajax({
	    url : 'http://query.yahooapis.com/v1/public/yql',

	 
	    // nazwa parametru wywołania zwrotnego
	    // określona przez serwis YQL
	    jsonp : 'callback',
	 
	    // przekaż jQuery, że chcesz otrzymać dane w formacie JSONP
	    dataType : 'jsonp',
	 
	    // przekaż serwisowi YQL jakich danych oczekujesz i że mają być to dane JSON
	    data : {
	        q : 'select title,abstract,url from search.news where query="cat"',
	        format : 'json'
	    },
	 
	    // zrób coś z odpowiedzią
	    success : function(odpowiedz) {
	        console.log(odpowiedz);
	    }
	});

Biblioteka jQuery obsługuje wszystkie skomplikowane aspekty formatu JSONP za nas — musimy tylko podać jej nazwę parametru wywołania zwrotnego JSONP, określonego przez serwis YQL (w tym przypadku jest to callback). Poza tym cały proces przebiega jak zwykłe żądanie Ajax.

Zdarzenia Ajax

Czasami chcemy wykonywać jakąś operację w momencie wysłania lub zakończenia żądania Ajax — na przykład pokazywać bądź ukrywać pasek pobierania. Zamiast definiować określone zachowanie wewnątrz każdego żądania, możemy powiązać zdarzenia Ajax z elementami, tak jak każde inne zdarzenie. Pełna lista zdarzeń Ajax dostępna jest na stronie http://docs.jquery.com/Ajax_Events.

Przykład 7.8. Ustawiamy pasek ładowania przy pomocy zdarzeń Ajax

$('#pasek_ladowania')
	    .ajaxStart(function() { $(this).show(); })
	    .ajaxStop(function() { $(this).hide(); });

Ćwiczenia

Załaduj zewnętrzną treść

Otwórz w przeglądarce plik /exercises/index.html, a także skorzystaj z pliku /exercises/js/load.js. Twoim zadaniem jest załadowanie treści wpisu blogowego, którego tytuł zostanie kliknięty przez użytkownika.

  1. Pod nagłówkiem każdego wpisu utwórz docelowy element div i za pomocą metody $.fn.data zachowaj do niego odniesienie w nagłówku.
  2. Do nagłówka podepnij zdarzenie click. Wywołanie go ma spowodować załadowanie przy pomocy metody $.fn.load odpowiedniej treści ze strony /exercises/data/blog.html do docelowego elementu div. Nie zapomnij zablokować domyślnej akcji zdarzenia.

Zwróć uwagę, że każdy nagłówek na stronie index.html zawiera odnośnik do danego wpisu. Do pobrania właściwej treści ze strony blog.html, będziesz potrzebować treści atrybutu href. Kiedy już go zdobędziesz, możesz przekształcić go w identyfikator, który może posłużyć jako selektor w metodzie $.fn.load. Oto jeden ze sposobów:

var href = 'blog.html#post1';
	var tempArray = href.split('#');
	var id = '#' + tempArray[1];

Pamiętaj, że zawsze możesz skorzystać z polecenia console.log, by upewnić się, że twoja praca idzie we właściwym kierunku!

Załaduj treść w formacie JSON

Otwórz w przeglądarce plik /exercises/index.html, a także skorzystaj z pliku /exercises/js/specials.js. Twoim zadaniem jest wyświetlić użytkownikowi szczegółowe informacje na temat nagrody specjalnej dostępne w wybranym przez niego dniu z rozwijanej listy.

  1. Za formularzem znajdującym się w elemencie #specials dodaj docelowy element div — będziesz w nim umieszczać otrzymane informacje na temat nagrody specjalnej.
  2. Powiąż zdarzenie change z elementem select. Kiedy użytkownik wybierze nowy element, wyślij żądanie Ajax do obiektu /exercises/data/specials.json.
  3. Kiedy odpowiedź JSON zostanie zwrócona, użyj wybranej przez użytkownika wartości (wskazówka: $.fn.val) do wyszukania w odpowiedzi informacji na temat nagrody.
  4. Do docelowego elementu div dodaj fragment kodu HTML z informacjami na temat nagrody.
  5. Na koniec usuń z formularza przycisk submit — formularz jest już obsługiwany przez Ajax.

Zauważ, że dane JSON są ładowane za każdym razem, gdy użytkownik wybiera inny element. Jakie zmiany należałoby wprowadzić w kodzie, aby żądanie wysyłane było tylko raz, a po wybraniu nowego elementu przez użytkownika zwracana byłaby odpowiedź przechowywana w pamięci podręcznej przeglądarki?

Autor: Rebecca Murphey

Źródło: http://github.com/rmurphey/jqfundamentals

Tłumaczenie: Joanna Liana

Treść tej strony jest dostępna na zasadach licencji CC BY-SA 3.0 US

1 komentarz do “Rozdział 7. Ajax”

Możliwość komentowania została wyłączona.