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 totrue
. 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 formatuscript
ijsonp
. 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ślniethis
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
lubGET
. Domyślna wartość parametru toGET
. Istnieje możliwość ustawienia innych żądań, np.PUT
lubDELETE
, 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. - 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.
- Pod nagłówkiem każdego wpisu utwórz docelowy element div i za pomocą metody
$.fn.data
zachowaj do niego odniesienie w nagłówku. - 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 elementudiv
. Nie zapomnij zablokować domyślnej akcji zdarzenia. - Za formularzem znajdującym się w elemencie
#specials
dodaj docelowy elementdiv
— będziesz w nim umieszczać otrzymane informacje na temat nagrody specjalnej. - Powiąż zdarzenie change z elementem select. Kiedy użytkownik wybierze nowy element, wyślij żądanie Ajax do obiektu /exercises/data/specials.json.
- 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. - Do docelowego elementu div dodaj fragment kodu HTML z informacjami na temat nagrody.
- Na koniec usuń z formularza przycisk submit — formularz jest już obsługiwany przez Ajax.
Każda z tych metod przyjmuje poniższe argumenty w następującej kolejności:
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.
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.
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?
Super artykuł. Jasno, po kolei, przystępnie. Dzięki