Datei wird geladen, bitte warten...
Zitiervorschau
Tytuł oryginału: Beginning Ajax Tłumaczenie: Anna Trojan ISBN: 978-83-246-8458-8 Copyright © 2007 by Wiley Publishing, Inc., Indianapolis, Indiana. All rights reserved. This translation published under license with the original publisher John Wiley & Sons, Inc. The Wrox Brand trade dress is a trademark of John Wiley & Sons, Inc. in the United States and/or other countries. Used by permission. Wiley and the Wiley logo, Wrox, the Wrox logo, Programmer to Programmer, are trademarks or registered trademarks of John Wiley and Sons, Inc. and/or its affiliates in the United States and other countries, and may not be used without written permission. All other trademarks are the property of their respective owners. Wiley Publishing Inc. is not associated with any product or vendor mentioned in this book. Translation copyright © 2008 by Wydawnictwo Helion S.A. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 032 231 22 19, 032 230 98 63 e-mail: [email protected] WWW: http://helion.pl (księgarnia internetowa, katalog książek) Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie?ajaodp_ebook Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/ajaodp.zip Printed in Poland.
Poleć książkę na Facebook.com
Księgarnia internetowa
Kup w wersji papierowej
Lubię to! » Nasza społeczność
Oceń książkę
Wyrazy miłości dla mojej żony Kate oraz chłopców. — Chris Ullman Z wyrazami miłości oraz podziękowaniami dla Waliego za znoszenie trudów bycia mężem pisarki; dla mojej matki Doris Dykes za zaszczepienie we mnie miłości do czytania oraz książek; dla wszystkich pionierów Internetu oraz innowatorów, którzy podzielili się swoją wiedzą z nami wszystkimi. — Lucinda Dykes
Podziękowania Dziękuję współautorce książki Lucindzie za to, że zawsze była dostępna, gdy chciałem o coś spytać lub poprosić o komentarz. Dziękuję Kevinowi Shaferowi za jego bardzo konsekwentny — ale wyważony — wpływ na pisany przeze mnie tekst. Dziękuję Alexeiowi Gorkovowi za celne i cięte komentarze na temat rozdziałów oraz kodu. Dziękuję również Jimowi Minatelowi za to, że mogłem go bezkarnie zasypywać licznymi pytaniami. — Chris Ullman Dziękuję współautorowi książki Chrisowi za wszystko, czego się od niego nauczyłam na temat programowania po stronie serwera. Dziękuję Kevinowi Shaferowi za tolerowanie wszystkich dziwactw będących konsekwencją sytuacji, w której dwóch autorów pracuje nad jedną książką, mieszkając daleko od siebie. Dziękuję Alexeiowi Gorkovowi za wyśmienitą korektę merytoryczną oraz sugestie dotyczące kodu. Dziękuję również Jimowi Minatelowi za jego niezwykle cenne sugestie oraz za to, że zawsze był dostępny i chętny do odpowiadania na nasze pytania. Jestem mu również wdzięczna za to, że umożliwił mi wzięcie udziału w tym projekcie. — Lucinda Dykes
Spis treści O autorach . ................................................................................................................................................13 Wprowadzenie . .........................................................................................................................................15 Rozdział 1. Wprowadzenie do Ajaksa . .....................................................................................................23 Czym jest Ajax? . .......................................................................................................... 24 Ajax w praktyce . ..................................................................................................... 25 flickr . .................................................................................................................... 25 Basecamp . ............................................................................................................ 27 Amazon (A9.com) . .................................................................................................. 28 Google Suggest oraz Google Maps ........................................................................... 29 Inne strony internetowe . ......................................................................................... 30 Złe przykłady . ........................................................................................................ 31 Ajax — akronim . .................................................................................................... 32 XHTML oraz CSS . .............................................................................................. 33 DOM (Document Object Model) . ......................................................................... 34 JavaScript . ....................................................................................................... 35 XML, XSLT oraz XPath . ...................................................................................... 36 Obiekt XMLHttpRequest . ................................................................................... 37 Technologie po stronie serwera . ........................................................................ 39 Model aplikacji opartej na Ajaksie . ................................................................................ 39 Dlaczego powinno się używać Ajaksa? . .................................................................... 41 Częściowe uaktualnianie strony . ........................................................................ 41 Niewidoczne pobieranie danych . ........................................................................ 42 Ciągłe uaktualnianie . ........................................................................................ 42 Jednolite interfejsy . ........................................................................................... 42 Prostota i bogactwo możliwości . ......................................................................... 42 Przeciąganie i upuszczanie . ............................................................................... 42 Kiedy nie należy używać Ajaksa . .............................................................................. 43 Spowolnienie strony . ......................................................................................................... 43 Zakłócenie działania przycisku Wstecz w przeglądarce . ........................................................ 43 Zakłócanie działania zakładek oraz blokowanie indeksów wyszukiwarek . ............................... 44 Obciążenie dla przeglądarki . .............................................................................................. 44 Kto może bądź nie może używać Ajaksa? ....................................................................... 44 Stwórz swój własny przykład . ........................................................................................ 45 Podsumowanie . .......................................................................................................... 55 Ćwiczenia . .................................................................................................................. 55
6
Ajax. Od podstaw Rozdział 2. Powtórka z JavaScriptu . .....................................................................................................57 Jądro JavaScriptu . ....................................................................................................... 58 Składnia . ............................................................................................................... 58 Zmienne . ............................................................................................................... 58 Podstawowe typy danych . .................................................................................. 59 Referencyjne typy danych . ................................................................................. 60 Operatory . ............................................................................................................. 60 Operator przypisania . ........................................................................................ 61 Operatory arytmetyczne . .................................................................................... 61 Operatory porównania . ...................................................................................... 61 Operatory logiczne . ........................................................................................... 62 Operatory inkrementacji oraz dekrementacji . ....................................................... 63 Instrukcje . ............................................................................................................. 63 Instrukcje warunkowe . ....................................................................................... 64 Pętle . ............................................................................................................... 65 Funkcje . ..................................................................................................................... 66 JavaScript zorientowany obiektowo . .............................................................................. 67 Obiekty wbudowane . .............................................................................................. 68 Obiekty przeglądarki . .............................................................................................. 68 Obiekty zdefiniowane przez użytkownika . .................................................................. 69 Konstruktory . .................................................................................................... 70 Prototypy . .............................................................................................................. 71 Niszczenie obiektów . ......................................................................................... 72 DOM (Document Object Model) . ................................................................................... 74 Dokument jako drzewo potomków . .......................................................................... 75 Dokument jako drzewo węzłów . ............................................................................... 75 Metody dostępu do obiektów w DOM . ...................................................................... 76 Metoda getElementById . ................................................................................... 76 Metoda getElementsByTagName . ....................................................................... 77 Tworzenie węzłów . ....................................................................................................... 78 Alternatywne rozwiązanie — innerHTML ......................................................................... 80 JavaScript oraz zdarzenia . ............................................................................................ 81 Modele zdarzeń . .................................................................................................... 82 Rejestracja zdarzeń . ............................................................................................... 82 Model rejestracji zdarzeń w przeglądarce Internet Explorer . .................................. 83 Model rejestracji zdarzeń w DOM z W3C . ............................................................ 84 Obiekty zdarzeń . ......................................................................................................... 84 Podsumowanie . .......................................................................................................... 88 Ćwiczenia . .................................................................................................................. 89
Rozdział 3. Ajax oraz technologie po stronie serwera ...........................................................................91 Ajax oraz technologie po stronie serwera . ...................................................................... 92 Formularze oraz kontrolki HTML .................................................................................... 92 Model przesyłania formularzy ........................................................................................ 92 Model przesyłania formularzy w Ajaksie oraz JavaScripcie ................................................ 94 Od strony serwera . ...................................................................................................... 94 Przesyłanie danych do serwera . .................................................................................... 95 Serwer otrzymuje żądanie . ........................................................................................... 95 Pisanie odpowiedzi HTTP . ............................................................................................ 96 Obiekt XMLHttpRequest . ........................................................................................ 97 Funkcja zwrotna . ............................................................................................... 98 Właściwość responseText . ................................................................................. 98
Spis treści
7
Właściwość responseXML . ................................................................................ 99 Usuwanie błędów z responseXML . ................................................................... 100 Wykorzystywanie danych . ................................................................................. 101 Technologie po stronie serwera . ................................................................................. 102 ASP.NET . ............................................................................................................. 102 Przykład wykorzystujący Ajaksa oraz ASP.NET . ................................................... 104 PHP . ................................................................................................................... 114 Przykład wykorzystujący Ajaksa oraz PHP . ......................................................... 115 Serwlety Javy . ...................................................................................................... 120 Przykład wykorzystujący Ajaksa oraz serwlety Javy . ............................................ 121 Którą technologię powinno się wykorzystywać? . ........................................................... 125 Podsumowanie . ........................................................................................................ 126 Ćwiczenia . ................................................................................................................ 126
Rozdział 4. Techniki Ajaksa ....................................................................................................................127 Obiekt XMLHttpRequest . ............................................................................................ 128 Tworzenie obiektu XMLHttpRequest . ........................................................................... 129 Użycie synchroniczne . ........................................................................................... 129 Użycie asynchroniczne . ......................................................................................... 130 Właściwość readyState . ........................................................................................ 130 Właściwości oraz metody obiektu XMLHttpRequest . ................................................ 131 Często popełniane błędy . ...................................................................................... 137 Bardziej skomplikowane problemy . ........................................................................ 138 Problem z tym samym pochodzeniem . .............................................................. 138 Kontrola pamięci podręcznej — agresywna polityka przeglądarki Internet Explorer .... 139 Implikacje działania we wszystkich przeglądarkach . ........................................... 143 Metoda POST . ........................................................................................................... 144 Zalety i wady używania metod POST oraz GET . ............................................................. 147 Inne techniki Ajaksa . ................................................................................................. 147 Ukryte ramki . ....................................................................................................... 147 Pomysł . .......................................................................................................... 148 Zalety oraz wady . ............................................................................................ 154 Ukryte ramki typu iframe . ...................................................................................... 154 Pomysł . .......................................................................................................... 155 Zalety oraz wady . ............................................................................................ 158 Dynamiczne ładowanie skryptu . ............................................................................. 158 Pomysł . .......................................................................................................... 158 Zalety oraz wady . ............................................................................................ 161 Obrazki oraz cookies . ........................................................................................... 161 Pomysł . .......................................................................................................... 162 Zalety oraz wady . ............................................................................................ 166 Podsumowanie . ........................................................................................................ 166 Ćwiczenie . ................................................................................................................ 167
Rozdział 5. Praca z XML . ........................................................................................................................169 Podstawy XML . .......................................................................................................... 170 Tworzenie znaczników . ............................................................................................... 170 Składnia XML . .......................................................................................................... 170 Dokumenty XML poprawne składniowo oraz strukturalnie .............................................. 172 Ekstrakcja danych za pomocą JavaScriptu . .................................................................. 177 Wykorzystywanie węzłów . ...................................................................................... 177 Dostęp do elementów XML po ich nazwie . .............................................................. 179 Dostęp do wartości atrybutów . .............................................................................. 179
8
Ajax. Od podstaw Wykorzystywanie CSS z danymi XML . .......................................................................... 183 Wykorzystywanie CSS z dokumentami XML . ............................................................ 185 Wykorzystywanie CSS z Ajaksem . .......................................................................... 185 Właściwość style . ........................................................................................... 185 Właściwość className . .................................................................................. 186 Podsumowanie . ........................................................................................................ 186 Ćwiczenia . ................................................................................................................ 187
Rozdział 6. Usuwanie oraz obsługa błędów ...........................................................................................189 Obsługa błędów w JavaScripcie . ................................................................................. 190 Obsługa wyjątków . .................................................................................................... 190 Program obsługi zdarzeń onerror ................................................................................. 192 Konsola błędów w przeglądarkach Mozilla .................................................................... 194 Microsoft Script Debugger .......................................................................................... 196 Firebug . .................................................................................................................... 199 Inspektory DOM . ....................................................................................................... 202 Inspektor DOM z przeglądarki Firefox ........................................................................... 202 Inspektor DOM w przeglądarce Internet Explorer ........................................................... 204 MODI (Mouseover DOM Inspector) .............................................................................. 204 Rozwiązywanie problemów związanych z Ajaksem . ........................................................ 205 Wykorzystywanie dodatku Firebug z XMLHttpRequest .................................................... 206 Dodatek Live HTTP Headers . ...................................................................................... 206 Podsumowanie . ........................................................................................................ 208 Ćwiczenia . ................................................................................................................ 209
Rozdział 7. Usługi sieciowe, API oraz aplikacje typu mashup . .............................................................211 Czym jest usługa sieciowa? . ....................................................................................... 212 Publiczne usługi sieciowe . .................................................................................... 213 Wykorzystywanie usług sieciowych należących do innych podmiotów . ............................. 214 Struktura usługi sieciowej . ......................................................................................... 216 Podejście oparte na REST . ......................................................................................... 217 Podejście oparte na SOAP .......................................................................................... 218 Integrowanie usługi sieciowej z własną aplikacją opartą na Ajaksie . .............................. 219 Wykorzystywanie usługi z obiektem XMLHttpRequest . ............................................. 220 Polityka tego samego pochodzenia .............................................................................. 220 Tworzenie proxy dla aplikacji . ..................................................................................... 221 Sztuczka ze znacznikiem script ................................................................................... 228 Przyszłe alternatywy . ................................................................................................. 231 Wykorzystywanie API . ................................................................................................. 232 Różnica między usługami sieciowymi a API . ............................................................ 233 Google Maps API . ................................................................................................ 234 Klucz Google Maps API . ................................................................................... 234 Obiekt mapy . .................................................................................................. 234 Obiekt Geocode . ............................................................................................. 235 Metoda fabrykująca XMLHttpRequest . .............................................................. 236 Aplikacje typu mashup . .............................................................................................. 244 W jaki sposób Ajax ułatwia wykorzystywanie aplikacji typu mashup . ............................... 245 Wykorzystywanie Flickr API . ................................................................................... 246 Etykietki (lista ważona) . ........................................................................................ 246 Wykorzystywanie klucza Flickr API . ......................................................................... 247
Spis treści
9
Tworzenie przykładowej aplikacji . ........................................................................... 247 Dodawanie informacji o miejscu zrobienia zdjęcia w serwisie Flickr . ............................... 248 Wyświetlanie zdjęć z Flickr . ........................................................................................ 257 Podsumowanie . ........................................................................................................ 261 Ćwiczenia . ................................................................................................................ 262
Rozdział 8. XSLT oraz XPath . .................................................................................................................263 XSLT oraz jego cel . .................................................................................................... 264 Elementy XSLT . ......................................................................................................... 266 Element xsl:stylesheet . ........................................................................................ 266 Element xsl:output . .............................................................................................. 267 Element xsl:include . ............................................................................................. 268 Elementy xsl:template, xsl:apply-templates oraz xsl:call-template . ........................... 268 Atrybut match . ................................................................................................ 268 Atrybut name . ................................................................................................. 269 Parametry XSLT . ............................................................................................. 270 Element xsl:if . ..................................................................................................... 270 Elementy xsl:choose, xsl:when oraz xsl:otherwise . .................................................. 270 Znoszenie znaczenia specjalnego znaków w XSLT ......................................................... 271 Element xsl:for-each . ................................................................................................. 272 Element xsl:value-of . ................................................................................................. 272 Element xsl:sort . ....................................................................................................... 273 Element xsl:variable . ................................................................................................. 273 Obsługa XSLT w najważniejszych przeglądarkach . ......................................................... 274 Wykonywanie transformacji . ....................................................................................... 274 Wykonywanie transformacji w przeglądarce Internet Explorer ......................................... 274 Wykonywanie transformacji w przeglądarce Firefox ........................................................ 279 Wykonywanie transformacji po stronie serwera ............................................................. 281 Tworzenie arkusza stylów XSLT dla koszyka z zakupami . ............................................... 284 XPath oraz jego cel . ................................................................................................... 294 Podstawowe możliwości XPath . .................................................................................. 294 Wyrażenia XPath . ................................................................................................. 295 Kontekst bieżący . ........................................................................................... 295 Węzeł główny dokumentu . ............................................................................... 296 Element główny dokumentu . ............................................................................ 296 Rekurencyjne schodzenie w dół drzewa . ............................................................ 296 Określone elementy . ....................................................................................... 297 Funkcje XPath . ..................................................................................................... 297 Funkcja number . ............................................................................................................. 297 Funkcja position . ............................................................................................................ 298 Funkcja count . ................................................................................................................ 298 Formatowanie łańcuchów znaków . .................................................................................... 298 Funkcje arytmetyczne . ..................................................................................................... 299 Funkcje logiczne . ............................................................................................................ 299 Wykonywanie zapytań w dokumentach XML za pomocą XPath . ...................................... 300 Ulepszenie przykładu z koszykiem z zakupami, tak by używał on XSLT oraz Ajaksa ........... 305 Podsumowanie . ........................................................................................................ 313 Ćwiczenia . ................................................................................................................ 314
10
Ajax. Od podstaw Rozdział 9. Wzorce . .................................................................................................................................315 Podstawy wzorców projektowych . ................................................................................ 316 Sprawdzanie poprawności formularzy . ......................................................................... 317 Problem . .................................................................................................................. 317 Wzorzec . .................................................................................................................. 317 Dodatkowe informacje we wzorcach związanych z najeżdżaniem myszą na element ......... 325 Problem . .................................................................................................................. 325 Wzorzec . .................................................................................................................. 326 Wzorzec odpytywania serwera . ................................................................................... 333 Problem . .................................................................................................................. 333 Wzorzec . .................................................................................................................. 333 Wzorzec służący do tworzenia list opartych na przeciąganiu oraz upuszczaniu . ............... 343 Problem . .................................................................................................................. 343 Wzorzec . .................................................................................................................. 343 Wzorzec obsługi błędów . ............................................................................................ 357 Problem . .................................................................................................................. 358 Wzorzec . .................................................................................................................. 358 Podsumowanie . ........................................................................................................ 364 Ćwiczenia . ................................................................................................................ 365
Rozdział 10. Praca z danymi zewnętrznymi .........................................................................................367 Praca z kanałami informacyjnymi XML . ........................................................................ 368 RSS 0.9x . ................................................................................................................ 370 RSS 2.0 . .................................................................................................................. 371 RSS 1.0 . .................................................................................................................. 373 Atom . ....................................................................................................................... 374 Ekstrakcja danych z kanału informacyjnego XML . ......................................................... 376 Ekstrakcja danych w postaci XML ................................................................................ 376 Ekstrakcja danych w postaci łańcucha znaków ............................................................. 383 Budowanie czytnika kanałów online opartego na Ajaksie . .............................................. 385 Podsumowanie . ........................................................................................................ 396 Ćwiczenia . ................................................................................................................ 396
Rozdział 11. JSON . ...................................................................................................................................397 Składnia JSON . ......................................................................................................... 398 Typy danych JSON . .................................................................................................... 398 Literały obiektów . ...................................................................................................... 399 Literały tablic . ........................................................................................................... 400 Wykorzystywanie analizatora składniowego JSON .......................................................... 400 Formaty transmisji danych . ........................................................................................ 401 Ajax oraz JSON . ......................................................................................................... 403 Tworzenie żądania . ............................................................................................... 403 Analiza składniowa odpowiedzi . ............................................................................. 405 Wykorzystywanie metody eval() . ....................................................................................... 405 Wykorzystywanie parseJSON() . ......................................................................................... 406 Dodawanie danych JSON do strony internetowej ........................................................... 406 Wykorzystywanie JSON z PHP . .................................................................................... 410 Podsumowanie . ........................................................................................................ 412 Ćwiczenia . ................................................................................................................ 412
Spis treści
11
Rozdział 12. Zaawansowany przykład — lista sortowana . ................................................................413 Wykorzystywanie MySQL . ........................................................................................... 414 Tworzenie tabeli MySQL . ............................................................................................ 414 Dodawanie danych do tabeli . ..................................................................................... 416 Tworzenie połączenia z bazą danych ............................................................................ 417 Tworzenie zapytań do bazy danych . ............................................................................. 418 Uzyskanie aktualnych wartości pól ............................................................................... 419 Porządkowanie listy w kolejności . ............................................................................... 419 Edycja rekordów bazy danych . .................................................................................... 421 Wstawianie rekordu . .................................................................................................. 421 Usuwanie rekordu . .................................................................................................... 423 Wykorzystywanie biblioteki Scriptaculous w przeciąganiu oraz upuszczaniu . ................... 424 Tworzenie elementu typu Droppable ............................................................................ 424 Tworzenie elementu typu Sortable ............................................................................... 426 Interakcja z użytkownikiem — strona główna . .............................................................. 427 Wykorzystywanie Ajaksa do uaktualniania listy . ............................................................ 431 Tworzenie żądań POST . ............................................................................................. 432 Tworzenie żądań GET . ............................................................................................... 434 Przetwarzanie wyników . ............................................................................................. 435 Dodawanie stylu . ...................................................................................................... 437 Pliki . ........................................................................................................................ 437 Podsumowanie . ........................................................................................................ 438
Dodatek A Rozwiązania ćwiczeń . ..........................................................................................................439 Dodatek B Istniejące zasoby Ajaksa — platformy oraz biblioteki . .....................................................461 Dodatek C Istniejące zasoby JavaScriptu .............................................................................................471 Dodatek D Przewodnik po języku JavaScript ......................................................................................475 Skorowidz . .............................................................................................................................................523
12
Ajax. Od podstaw
O autorach Chris Ullman jest niezależnym programistą webowym oraz autorem książek technicznych, który spędził wiele lat, pracując w technologiach ASP oraz ASP.NET. Informatyk, zaczynał jako guru Uniksa i Linuksa, jednak w tak zwanym „lecie ASP” (1997 rok) przeniósł swoje zainteresowania na technologie firmy Microsoft. Zaczynał od pisania przewodników po ASP z wydawnictwa Wrox i do tej pory napisał bądź był współautorem ponad dwudziestu pięciu książek, z czego najbardziej znany jest jako główny autor bestsellerowej serii Beginning ASP/ASP.NET 1.x. Pisał rozdziały do książek o PHP, ColdFusion, JavaScripcie, usługach sieciowych, C#, XML oraz wielu innych technologiach powiązanych z Internetem. Do sierpnia 2001 roku był pełnoetatowym pracownikiem wydawnictwa Wrox. Później zajął się programowaniem w VB.NET oraz C#, a także ASP.NET i w kwietniu 2003 roku założył własną firmę — CUASP Consulting Ltd. Posiada kilka stron internetowych, w tym http://www.cuasp.co.uk (strona zawodowa) oraz http://www.atomicwise.com (artykuły na temat muzyki oraz sztuki). Obecnie dzieli swój czas pomiędzy rodzinę a komponowanie muzyki elektronicznej do swojego projektu muzycznego o nazwie Open E. Lucinda Dykes jest niezależnym programistą webowym, nauczycielem oraz autorem książek technicznych; programuje i tworzy strony internetowe od 1994 roku. Rozpoczęła swoją karierę w zaawansowanej technicznie dziedzinie medycyny, jednak porzuciła ten obszar na rzecz technologii oraz Internetu. Od wielu lat jest zaangażowana w programowanie po stronie klienta z wykorzystaniem JavaScriptu za pośrednictwem własnej firmy — Zero G Web. Prowadzi również dla międzynarodowej grupy studentów kursy internetowe, które można znaleźć na stronie www.eclasses.org. Jest autorką wielu książek na temat XML, XHTML oraz programowania aplikacji webowych z wykorzystaniem programu Dreamweaver.
14
Ajax. Od podstaw
Wprowadzenie Ajax stał się w ostatnich dwóch latach modnym terminem i często wymieniany jest obok drugiego modnego terminu — Web 2.0. Żaden z nich nie odnosi się do czegoś namacalnego, co można pobrać, jednak oba pojęcia zostały ukute w celu odzwierciedlenia zmieniającej się natury Internetu. Web 2.0 w takim samym stopniu polega na podejściu czy sposobie myślenia, jak na nowych technologiach. W ostatnich latach równocześnie pojawiło się wiele innowacji — wiki, blogi, kanały informacyjne RSS, API czy usługi sieciowe — które przyczyniły się do tych przemian. Ajax jest w wielu przypadkach ich podstawą. Ajax nie jest technologią samą w sobie, ale raczej parasolem, pod którym mieści się kilka istniejących już technologii, takich jak JavaScript, DOM (Document Object Model) oraz XML (Extensible Markup Language), które razem wykorzystywane są do tworzenia bardziej interaktywnych aplikacji webowych, eliminujących konieczność odświeżania całej strony, kiedy zmienia się tylko jej część. Choć termin „Ajax” pojawił się stosunkowo niedawno, technologie wykorzystywane w aplikacjach opartych na Ajaksie istnieją od wielu lat, a niektórzy programiści od dawna je wykorzystują. W ostatnim roku gwałtownie wzrosła jednak liczba stron internetowych wykorzystujących techniki Ajaksa. Co więcej, w wielu ofertach pracy wymaga się, by programiści znali się na tworzeniu aplikacji tego typu. Niniejsza książka ma na celu pomóc programistom w zrozumieniu podstawowych technologii kryjących się pod nazwą „Ajax”, a także pokazać, w jaki sposób można zacząć budować strony internetowe z wykorzystaniem technik Ajaksa. Choć wiele osób słyszało o Ajaksie, niewiele rozumie, w jaki sposób pisze się aplikacje webowe z wykorzystaniem tych technik. Ajax rozmywa tradycyjne granice pomiędzy programistami po stronie klienta oraz po stronie serwera i wymusza rozważenie na nowo tego, w jaki sposób powinno się tworzyć aplikacje, a także jakie możliwości powinien oferować interfejs użytkownika. Ajax nie wymaga nowego oprogramowania, nowych serwerów ani narzędzi. Opiera się na wykorzystywaniu tego, co jest już dostępne. Polega także na kwestionowaniu tego, że wszystko trzeba wykonywać na serwerze. Ajax to powrót do starych idei i tchnięcie w nie nowego życia. To fundamentalna zmiana sposobu, w jaki działa Internet.
16
Ajax. Od podstaw
Dla kogo przeznaczona jest ta książka Niniejsza książka uczy, w jaki sposób tworzy się aplikacje zgodnie z zasadami Ajaksa. Książka ta nie zakłada, że najlepszą przeglądarką jest Internet Explorer, Firefox czy Safari, i pokazuje przykłady działające we wszystkich najważniejszych przeglądarkach. Jednak ze względu na stopień skomplikowania Ajax nie jest zagadnieniem dla zupełnego nowicjusza. Czytelnik powinien być zaznajomiony z następującymi technologiami po stronie klienta:
HTML oraz XHTML,
JavaScript,
CSS (kaskadowe arkusze stylów).
Czytelnik powinien również znać przynajmniej jedną z poniższych technologii po stronie serwera:
PHP,
ASP.NET.
Przykłady po stronie serwera zostaną podane zarówno w PHP, jak i w ASP.NET, jednak zaawansowana znajomość tych technologii nie jest konieczna. Czytelnik nie musi znać żadnej z poniższych technologii, ponieważ przedstawione zostaną pełne wprowadzenia do każdej z nich (choć oczywiście ich znajomość może być przydatna):
DOM (Document Object Model),
XML,
XPath,
XSLT (Extensible Stylesheet Language Transformations),
usługi sieciowe (REST oraz SOAP).
Tak jak w przypadku innych książek z serii Od podstaw, koncepcje wprowadzone w jednych rozdziałach są następnie rozszerzane oraz wykorzystywane w kolejnych.
Co omawia niniejsza książka Niniejsza książka omawia, czym jest Ajax oraz co owa technologia znaczy dla programistów webowych; przedstawia również technologie stojące za aplikacjami opartymi na Ajaksie. Początkowe rozdziały książki rozpoczynają się od omówienia zalet oraz wad Ajaksa, a także odświeżają wiedzę na temat JavaScriptu. Wraz z lekturą książki będzie można zobaczyć, w jaki sposób techniki Ajaksa radzą sobie z programowaniem po stronie klienta oraz serwera, jakie są popularne wzorce Ajaksa, a także jak Ajax łączy się z technologiami takimi, jak XSLT, usługi sieciowe oraz DOM. W ostatnim rozdziale zamieszczono rozszerzone omówienie tworzenia aplikacji opartej na Ajaksie.
Wprowadzenie Poniżej znajduje się opis zawartości kolejnych rozdziałów książki:
Rozdział 1., „Wprowadzenie do Ajaksa” — rozdział ten prezentuje obiektywną ocenę tego, czym jest Ajax, a także przedstawia, jakie są jego zalety oraz wady (bądź potencjalne wady). Omówiono w nim różne technologie, a także przedstawiono przykład dynamicznego menu, które pobiera wyświetlane wartości z pliku XML.
Rozdział 2., „Powtórka z JavaScriptu” — przed rozpoczęciem szczegółowego omawiania budowania aplikacji opartych na Ajaksie wszyscy Czytelnicy powinni posiadać wiedzę mniej więcej na tym samym poziomie. W rozdziale tym przedstawiono powtórkę z technik JavaScriptu oraz omówiono DOM wraz z wyjaśnieniem ważnej roli, jaką pełni on w aplikacjach opartych na Ajaksie.
Rozdział 3., „Ajax oraz technologie po stronie serwera” — choć Ajax w dużej mierze opiera się na budowaniu aplikacji za pomocą JavaScriptu i wywoływaniu serwera w tle, ważne jest również to, w jaki sposób serwer otrzymuje, przetwarza oraz zwraca dane. W tym rozdziale wprowadzono obiekt XMLHttpRequest i pokazano, w jaki sposób może on wywoływać aplikacje w ASP.NET, PHP oraz Javie. Omówiono również różne sposoby oraz formaty zwracania informacji z powrotem do klienta.
Rozdział 4., „Techniki Ajaksa” — w rozdziale tym zagłębiono się w szczegóły obiektu XMLHttpRequest. Omówiono różne techniki, które można uznać za techniki Ajaksa, bez względu na to, czy korzystają z obiektu XMLHttpRequest, ukrytych ramek, ukrytych ramek wewnętrznych, dynamicznego ładowania obrazków czy dynamicznego ładowania skryptu. Omówiono również scenariusze, w jakich techniki te mogą zostać wykorzystane.
Rozdział 5., „Praca z XML” — XML stał się standardem przechowywania danych w ustrukturyzowany sposób oraz transmitowania ich. Jedna z podstawowych technik Ajaksa obejmuje wykorzystanie obiektu XMLHttpRequest. Choć obiekt ten nie musi być używany w połączeniu z XML, jest jednak wykorzystywany przede wszystkim w takiej konfiguracji. Rozdział ten omawia zasady tworzenia dokumentów XML, a także sposoby wydajnej nawigacji po nich i wykonywania zapytań.
Rozdział 6., „Usuwanie oraz obsługa błędów” — programy typu IDE (Integrated Development Environment), takie jak Visual Studio .NET czy Dreamweaver, udostępniają użytkownikom zbiory narzędzi ułatwiających usuwanie błędów z aplikacji. Próby usuwania błędów bez takich aplikacji mogą być trudne. W tym rozdziale omówiono ręczne usuwanie błędów z JavaScriptu oraz pisanie programów obsługi błędów, które sprawiają, że aplikacja oparta na Ajaksie poradzi sobie z każdą ewentualnością.
Rozdział 7., „Usługi sieciowe, API oraz aplikacje typu mashup” — kolejnym elementem układanki Web 2.0 jest udostępnianie możliwości aplikacji przez wielkie firmy oraz korporacje. Każdy programista może teraz osadzać mapy, fotografie, prognozy pogody czy listy utworów do odtwarzania w aplikacjach — albo za pośrednictwem usług sieciowych, albo API. W tym rozdziale omówiono, w jaki sposób da się połączyć różne możliwości w celu utworzenia aplikacji ajaksowych typu mashup.
17
18
Ajax. Od podstaw
Rozdział 8., „XSLT oraz XPath” — XSLT oraz XPath są technologiami opartymi na XML, które udostępniają bardziej wydajne oraz elastyczne sposoby wykonywania zapytań do dokumentów XML oraz zwracania z nich danych (w miejsce wykorzystywania DOM oraz JavaScriptu). W rozdziale tym krótko przedstawiono składnie obu tych języków oraz pokazano, w jaki sposób mogą one zostać wykorzystane w celu uczynienia aplikacji bogatszą i bardziej przyjazną dla użytkownika.
Rozdział 9., „Wzorce” — programowanie opiera się na modularyzacji oraz ponownym wykorzystywaniu kodu. Te same problemy stale się powtarzają, a rozwiązania tworzone są z wykorzystaniem wypróbowanych oraz zaufanych technik zwanych wzorcami. Aplikacje oparte na Ajaksie nadają się do pewnych określonych zastosowań (na przykład sprawdzania poprawności formularzy czy uprzedniego ładowania strony). W tym rozdziale omówiono pewne często spotykane wzorce, w implementacji których można wykorzystać Ajaksa.
Rozdział 10., „Praca z danymi zewnętrznymi” — w tym rozdziale pokazano, w jaki sposób korzysta się z zewnętrznych kanałów informacyjnych, takich jak RSS czy Atom, a także w jaki sposób tworzy się aplikacje wykorzystujące dane pojawiające się w regularnych odstępach czasu. Omówiono również strukturę wymaganą w przykładowym kanale informacyjnym oraz to, co potrzebne jest aplikacji do odczytywania takich kanałów.
Rozdział 11., „JSON” — w tym rozdziale omówiono alternatywny format transmisji danych w JavaScripcie, czyli JSON (JavaScript Object Notation), który zwraca zbiór literałów tablic oraz obiektów. Przedstawiono, w rozwiązywaniu jakich problemów można wykorzystać ten format, a także w jaki sposób buduje się komponent zwracający ten format.
Rozdział 12., „Zaawansowany przykład — lista sortowana” — ostatni rozdział udostępnia sporą przykładową aplikację, która korzysta z biblioteki Scriptaculous oraz technik przedstawionych w niniejszej książce, w tym obiektu XMLHttpRequest, DOM oraz programów obsługi zdarzeń klawiatury.
Dodatek A, „Rozwiązania ćwiczeń” — rozwiązania wszystkich zadań przedstawionych w kolejnych rozdziałach książki.
Dodatek B, „Istniejące zasoby Ajaksa — platformy oraz biblioteki” — przewodnik omawiający, w jaki sposób instaluje się oraz wykorzystuje niektóre najbardziej popularne biblioteki oraz platformy, w tym Prototype, Scriptaculous, Dojo i inne.
Dodatek C, „Istniejące zasoby JavaScriptu” — lista użytecznych blogów, przewodników, samouczków, artykułów oraz stron internetowych poświęconych JavaScriptowi.
Dodatek D, „Przewodnik po języku JavaScript” — przegląd obiektów oraz konstrukcji języka JavaScript.
Wprowadzenie
19
Struktura książki Książka wyjaśnia wszystko krok po kroku, wykorzystując działające przykłady oraz szczegółowe omówienia w celu zademonstrowania, w jaki sposób tworzy się aplikacje oparte na Ajaksie. Choć nie każdy rozdział opiera się na poprzednim, w większości przypadków tak właśnie jest, dlatego w celu zrozumienia przedstawionych zagadnień najłatwiej będzie czytać książkę od początku do końca. Książki z serii „Od podstaw” wykorzystują podejście narracyjne, które jest metodyczne oraz przyjazne dla użytkownika. Budowane są zgodnie z filozofią, że najpierw przedstawia się to, co będzie się robić, następnie prezentuje przykład, a później omawia, co zrobiono. Autorzy książki (wraz z doskonałymi redaktorami) wspólnie pracowali nad tym, by pozycja ta była spójna i kompletna.
Co jest potrzebne do wykorzystywania tej książki By móc jak najwięcej skorzystać z niniejszej książki, należy zainstalować na swoim komputerze następujące oprogramowanie:
system operacyjny — przynajmniej Windows XP Professional bądź jakaś wersja Linuksa,
przynajmniej jeden z następujących serwerów — IIS bądź Apache,
przynajmniej jedną z technologii po stronie serwera — PHP (w wersji 5) bądź ASP.NET (w wersji 2.0),
przeglądarkę Internet Explorer 6 lub 7 bądź Mozilla Firefox w wersji 2,
edytor tekstowy (taki jak Notatnik bądź emacs).
Choć aplikacje oparte na Ajaksie nie muszą wywoływać kodu po stronie serwera, ich możliwości są znacznie ograniczone, jeśli tak nie jest. Wiele przykładów z książki wymaga serwera WWW z działającym PHP bądź ASP.NET. Każdy przykład podany jest w dwóch wersjach, z wyjątkiem rzadkich przypadków, które zostaną wcześniej zaznaczone.
Konwencje wykorzystywane w książce By w jak największym stopniu wykorzystać książkę i móc łatwo śledzić, co się w niej dzieje, w całym tekście wykorzystano kilka konwencji.
spróbuj sam W częściach „Spróbuj sam” znajdują się ćwiczenia, które powinno się śledzić zgodnie z tekstem książki.
20
Ajax. Od podstaw 1.
Przykłady składają się z kilku etapów.
2. Każdy etap jest ponumerowany. 3. Należy śledzić kolejne etapy wraz z własną kopią kodu. Można albo wpisywać
kod samodzielnie, albo pobrać go z serwera FTP (ftp://ftp.helion.pl/przyklady/ ajaodp.zip). Czasami zdarza się, że na serwerze dostępne są elementy (takie jak obrazki), które są niedostępne w książce. Nie są one jednak niezbędne do działania przykładów.
Jak to działa Po każdej części „Spróbuj sam” wpisany kod zostanie szczegółowo omówiony. Ramki takie jak ta zawierają ważne informacje, o których nie należy zapominać, odnoszące się bezpośrednio do otaczającego je tekstu.
Wskazówki, uwagi i sztuczki odnoszące się do aktualnego tekstu są umieszczane w takich wyróżnieniach. Jeśli chodzi o style stosowane w tekście:
Nowe pojęcia oraz ważne słowa są przy ich wprowadzaniu pisane kursywą.
Kombinacje klawiszy zapisano jako Ctrl+A.
Nazwy plików oraz adresy URL w tekście widoczne są jako kursywa, jak www.helion.pl.
Kod znajdujący się w tekście zapisany jest czcionką o stałej szerokości, jak persistence.properties.
Kod zapisany samodzielnie pojawia się w dwóch formatach:
W przykładach nowy lub istotny kod został umieszczony w ramce. Ramki nie mają te fragmenty kodu, które są mniej ważne bądź zostały zaprezentowane wcześniej.
Kod źródłowy Pracując z przykładami z książki, można albo zdecydować się na samodzielne ich wpisywanie, albo skorzystać z kodów źródłowych towarzyszących książce. Wszystkie kody źródłowe książki można pobrać ze strony http://helion.pl/ksiazki/ajaodp.htm; znajdują się one pod odnośnikiem Przykłady na ftp. Po pobraniu kodu należy rozpakować go za pomocą ulubionego narzędzia.
Wprowadzenie
21
Errata Autorzy oraz redaktorzy książki wspólnie podjęli wysiłki mające na celu zapewnienie, by w tekście książki oraz w kodach nie było błędów. Nikt nie jest jednak idealny, błędy mogą się zatem pojawić. Jeśli w książce wydawnictwa Helion odnaleziono błąd (na przykład literówkę bądź niepoprawny fragment kodu), redakcja będzie bardzo wdzięczna za zgłoszenie takiego przypadku. Przesyłając erratę, można oszczędzić innym Czytelnikom frustracji oraz straconego czasu i jednocześnie pomóc nam w udostępnianiu informacji najwyższej jakości. Żeby zgłosić błąd znaleziony w książce wydawnictwa Helion, należy przejść na stronę www.helion.pl, a następnie wyszukać odpowiedni tytuł. Na stronie książki należy następnie wybrać odnośnik zgłoś erratę. Można również przejść bezpośrednio na stronę http://helion.pl/ user/erraty/ i wybrać odpowiednią książkę z listy. Żeby sprawdzić, czy znaleziony błąd nie został już zgłoszony, należy kliknąć odnośnik Errata na stronie książki (obecny jedynie w przypadku tytułów, które posiadają już erratę). Zgłoszenia błędu można również dokonać, wysyłając e-mail na adres [email protected]. Po otrzymaniu zgłoszenia błędu redakcja sprawdzi informacje i opublikuje je w erracie znajdującej się na stronie książki oraz w przyszłych wydaniach drukowanych.
22
Ajax. Od podstaw
1
Wprowadzenie do Ajaksa Ścieżka historii usłana jest podziałami, rozłamami i rozważaniami na temat tego, „co by było, gdyby…”. Tempo rozwoju technologii jest nieubłagane i często również bezlitosne. W przeszłości można było obserwować zwycięstwo technologii VHS nad Betamax, komputerów PC nad mikrokomputerami, przeglądarki Internet Explorer (IE) nad Netscape Navigator, a wiele podobnych konfliktów w dziedzinie formatów DVD czeka na swoje rozstrzygnięcie. Nie oznacza to, że jedna technologia była akurat o wiele lepsza od innej; często bywa tak, że jeden format czy wynalazek ma cechy i możliwości wymagane w danym czasie, co wystarczy, by stał się on bardziej popularny. Nadal można spotkać entuzjastów, którzy z rozrzewnieniem wspominają zalety taśm Betamax, twierdząc, że były one mniejsze, miały lepszą jakość i tak dalej. Nie oznacza to jednak, że osoby takie nie miały racji. Być może teraz są one nieco przygnębione i popadają w przesadę, jednak tak naprawdę w tym, co mówią, coś jest. Ewolucja Internetu także ma za sobą kilka takich rozłamów. Jednym z tych, których echa pobrzmiewają do dziś, jest „debata” pomiędzy tak zwanymi „fat-client” a „thin-client”. W skrócie mówiąc, chodzi o wybór pomiędzy wykonywaniem większości pracy przez przeglądarkę a wykonaniem całego przetwarzania po stronie serwera. Na początku, w połowie lat dziewięćdziesiątych ubiegłego stulecia, wszystko wskazywało na to, że wygra ideologia „fat-client”. Wprowadzenie przeglądarek Internet Explorer 4 (IE4) oraz Netscape Navigator 4 spowodowało rozwój dynamicznego HTML (DHTML) wykorzystującego języki skryptowe do zmiany stron, by możliwe było przeciąganie i upuszczanie elementów bądź pokazywanie menu i ukrywanie go bez odświeżania strony. W ciągu kolejnego roku gwałtowną popularnością zaczęła się jednak cieszyć koncepcja „thin-client” — dzięki wprowadzeniu technologii po stronie serwera, takich jak Active Server Pages czy PHP. Techniki po stronie klienta nadal istnieją, jednak obecnie powszechnie stosowany model Internetu oraz stron internetowych oparty jest w dużej mierze na metodzie „wprowadź dane, wyślij stronę do serwera, poczekaj na odpowiedź”. Kiedy jeden format przeważa, w masowym pędzie do przyjmowania go często zapomina się o tym, co było zaletą drugiego formatu. Przykładowo pewne formy sprawdzania poprawności danych równie dobrze mogą być wykonywane w przeglądarce. Gdyby w polu tekstowym z adresem e-mail wpisano na przykład „to jest mój adres e-mail”, nie byłoby konieczne odwołanie się do serwera w celu sprawdzenia tych danych. Choć wiele osób rozsądnie
24
Ajax. Od podstaw dzieli sprawdzanie poprawności danych pomiędzy klienta i serwer, na wielu stronach internetowych próbuje się przerzucić cały ten proces na serwer. Gdyby spróbować wymienić jeden najważniejszy zarzut pod adresem Internetu, byłaby to zapewne jego ograniczona szybkość. Przekroczenie czasu odpowiedzi, błędy typu „Nie znaleziono strony”, nieodpowiadające przyciski oraz nieaktualne odnośniki — wszystkie te problemy nie zniknęły pomimo tego, że przepustowość łączy wzrosła dziesięciokrotnie. Coraz popularniejsze stają się inne metody radzenia sobie z tą powolnością. Firmy zaczęły sprawdzać, czy są w stanie jakoś poprawić interakcję z użytkownikiem na kilku poziomach, sprawiając, że strony staną się szybsze i będą lepiej reagować na działania użytkownika, ale także będą oferowały bogatsze możliwości. Często działania te obejmują również powrót do pewnych starych pomysłów. Pierwszym i najlepszym przykładem tworzenia aplikacji webowych w ten „nowy” sposób był Gmail firmy Google. Firma wykorzystała również te techniki w aplikacjach takich, jak Google Suggest czy Google Maps, choć żadna z tych aplikacji nie stanowi aż tak dobrego przykładu ani też nie jest równie popularna jak Gmail. Windows Live Mail (wcześniej zwany Kahuna), wyszukiwarka Amazon A9.com, flickr.com firmy Yahoo! służący do organizowania zdjęć w Internecie — wszystkim tym aplikacjom brakowało wspólnego sposobu opisania udostępnianych możliwości, dopóki w 2005 roku w Internecie nie pojawił się artykuł nadający im nazwę Ajax.
Czym jest Ajax? Ajax to chwytliwa nazwa wymyślona przez Jesse Jamesa Garretta na potrzeby artykułu napisanego dla Adaptive Path w 2005 roku, zatytułowanego Ajax: A New Approach to Web Applications, który nadal można znaleźć na stronie http://adaptivepath.com/publications/ essays/archives/000385.php. Artykuł ten powinien przeczytać każdy (o ile już tego nie zrobił), jednak dopiero po skończeniu lektury niniejszego rozdziału, ponieważ może on być nieco mylący w kwestii tego, czym dokładnie jest Ajax. Ajax jest również akronimem, jednak z pewnych przyczyn odłóżmy na razie wyjaśnienie tego, co oznacza ta nazwa. Ajax nie istniał przed tym artykułem, jednak możliwości opisane w artykule z pewnością istniały. W skrócie, Ajax jest zbiorem technik związanych z programowaniem czy też, ogólnie, pewnym podejściem do programowania webowego. Techniki te obejmują płynne uaktualnianie strony internetowej bądź jej części z otrzymaniem danych z serwera, jednak bez konieczności wykonania natychmiastowego odświeżenia strony. Nie oznacza to, że przeglądarka nie łączy się z serwerem WWW. Tak naprawdę w wyżej wspomnianym artykule zarysowano nieco niekompletny obraz sytuacji, gdyż nie wspomniano o tym, iż technologie po stronie serwera nadal często są niezbędne. Jest wysoce prawdopodobne, że strona internetowa bądź dane, z których jest ona budowana, nadal muszą w którymś momencie zostać uaktualnione za pomocą kontaktu z serwerem. Tym jednak, co odróżnia model Ajaksa od modelu klasycznego, jest to, że przesunięto moment, w którym strona jest uaktualniana. Oba modele zostaną wkrótce omówione nieco bardziej szczegółowo. Artykuł Garretta przedstawiał świat, w którym aplikacje webowe odzwierciedlałyby aplikacje desktopowe, jeśli chodzi o możliwości. Kluczowymi słowami były „bogactwo”, „lepsza interakcja”, „prostota”. Garrett wyobrażał sobie nowy gatunek aplikacji, który mógłby wypełnić lukę istniejącą pomiędzy aplikacjami desktopowymi a webowymi. Wymieniał Gmail, Google Suggest oraz Google Maps jako sztandarowe przykłady tego nowego podejścia.
Rozdział 1.
Wprowadzenie do Ajaksa
25
Artykuł — a nawet termin „Ajax” — spolaryzował społeczność programistów. Choć wiele osób pokochało to podejście i stało się jego wyznawcami, spora rzesza programistów krytykowała różne jego aspekty, od nazwy „Ajax” (określanej jako banalna) po opisane techniki, które w żaden sposób nie były nowe. Narzekania w dużej mierze przypominały typową krytykę przeciwnika sztuki współczesnej: „Hej, też mogę zrobić coś takiego, tak samo zresztą jak moja dziesięcioletnia córka”. Samo to, że ludzie mogli wykorzystywać te techniki do tworzenia własnych stron oraz aplikacji, nie oznaczało, że tak robili. Niestety, królowały zazdrość i szkalowanie. W rezultacie jednak pojawiła się zgoda co do tego, że techniki i pomysły opisane przez Jesse Jamesa Garretta dotknęły czułej struny (pojawiły się komentarze typu: „Gdybyśmy od nowa projektowali Internet pod kątem aplikacji, na pewno nie kazalibyśmy użytkownikom ciągle czekać” czy „Przed projektantami tego typu aplikacji stoją wyzwania takie, jak konieczność zapomnienia o tym, co obecnie wiemy na temat ograniczeń Internetu, i wyobrażenia sobie szerszych, bogatszych możliwości”). Było to wezwanie do walki, do wykorzystywania istniejących i stabilnych metod tworzenia aplikacji webowych zamiast pośpiesznego łapania najnowszego programu w niedojrzałej wersji beta. Programistów przekonywano do wykorzystywania istniejącej wiedzy na temat JavaScriptu, arkuszy stylów, a także DOM (Document Object Model) zamiast tracenia czasu i sił na opanowanie najnowszego języka budowy stron internetowych opartego na znacznikach. To było wyzwolenie, a już niedługo potem ogłoszenia z ofertami pracy zostały przeformułowane na: „Poszukiwany programista z pięcioletnim doświadczeniem w JavaScripcie oraz Ajaksie”. Tak naprawdę nie pokazuje to jednak, co robi sam Ajax, więc, jak zwykle, najlepiej będzie przyjrzeć się z bliska technikom ajaksowym wykorzystywanym obecnie w Internecie.
Ajax w praktyce Bez wątpienia najważniejszą aplikacją opartą na Ajaksie jest Gmail, pozwalający użytkownikom na uaktualnianie odebranych wiadomości e-mail bez setki odświeżeń strony. Aplikacja ta natychmiast przekonała osoby, które dotychczas korzystały z programów takich, jak Outlook, Outlook Express czy Thunderbird na własnych komputerach, do przejścia na internetowy system e-mail. Niestety, aplikacji Gmail nie da się zaprezentować bez rejestracji, a rejestracje możliwe są obecnie jedynie w ograniczonej liczbie krajów1. Trzeba zatem będzie przyjrzeć się innym przykładom.
flickr Strona flickr.com należąca do Yahoo! to serwis organizujący zdjęcia, pozwalający na „sortowanie, przechowywanie, wyszukiwanie i prezentację zdjęć w Internecie”. Wcześniej flickr wykorzystywał technologię Flash jako główne narzędzie interfejsu prezentującego zdjęcia, jednak w maju 2005 roku ogłoszono, iż serwis będzie wykorzystywał dynamiczny HTML oraz Ajaksa (http://blog.flickr.com/en/2005/05/12/from-flash-to-dhtml-on-some-pages/, http://blog.flickr.com/en/2005/05/12/news-2005-5-12/). Żeby móc zobaczyć działanie tego 1
Obecnie możliwe jest już rejestrowanie się we wszystkich krajach, a system zaproszeń został zniesiony — przyp. tłum.
26
Ajax. Od podstaw narzędzia w praktyce, należy zarejestrować się w serwisie. Ponieważ jest on darmowy, a poza tym narzędzia pozwalające na obróbkę zdjęć w aplikacjach webowych są wspaniałym sposobem na zademonstrowanie technik Ajaksa, zdecydowanie warto spróbować. Po zalogowaniu można uzyskać dostęp do odpowiedniego narzędzia za pomocą menu Organize, wybierając opcję Organize All Your Photos (rysunek 1.1). Można przeciągać i upuszczać zdjęcia do jednej grupy, a także obracać je i poprawiać ich etykiety.
Rysunek 1.1. Opcja Organize your photos we flickr
Wszystko to odbywa się gładko za pomocą Ajaksa. Dodatkowo przyciski takie, jak Send to Group, Add to Set oraz Blog this pozwalają na wykonywanie odpowiednich czynności bezpośrednio na stronie. Serwis flickr wspomina nawet, że do osiągnięcia tego wszystkiego wykorzystywana jest „stara technologia”. Techniki dynamicznego HTML zastąpiły technologię Flash, ponieważ Flash wymaga posiadania najnowszej wersji wtyczki Macromedia, a także może się długo ładować. Użytkownicy wcześniej na to narzekali. Flash jest świetną aplikacją, jednak w tym kontekście Ajax okazał się bardziej wydajny.
Rozdział 1.
Wprowadzenie do Ajaksa
27
Basecamp Basecamp jest webowym narzędziem do zarządzania projektami oraz śledzenia ich. Można je znaleźć na stronie www.basecamphq.com. I znów konieczne jest zarejestrowanie się na stronie, jednak istnieje możliwość zrobienia tego za darmo, z dość rozsądnym zakresem możliwości do wykorzystania. Basecamp wykorzystuje Ajaksa do dodawania osób do firmy, dodawania firm do projektu, dodawania, edytowania, usuwania, zmiany kolejności, wypełniania elementów do zrobienia, dodawania, usuwania, edytowania i zmiany kolejności list elementów do zrobienia, a także dodawania, edytowania i usuwania elementów związanych z czasem oraz zmiany nazwy załączników wiadomości (rysunek 1.2).
Rysunek 1.2. Dodawanie osób do firmy w aplikacji Basecamp
Kiedy kliknie się odnośnik do dodawania osób do firmy, bez odświeżenia strony gładko wysuwa się obszar okna dialogowego. Panel z wskazówkami znika z kolei, kiedy wybierze się przycisk Don’t show this again.
28
Ajax. Od podstaw Nie wszystkie elementy Basecamp wykorzystują Ajaksa, jednak wrażenie robi połączenie interakcji po stronie serwera z technikami Ajaksa, które nie są nadużywane, a jedynie wykorzystywane wtedy, gdy będzie to z największą korzyścią dla użytkownika.
Amazon (A9.com) Amazon to znany sklep internetowy, jednak nieco mniej znana jest jego wyszukiwarka www.A9.com, która łączy wyniki wyszukiwania z wielu różnych źródeł. Od momentu pojawienia się na rynku wyszukiwarek pozostały one w zasadzie niezmienione, jeśli chodzi o interfejs użytkownika. Wpisuje się słowo, a następnie klika przycisk Szukaj (bądź Search w przypadku serwisów anglojęzycznych). Zmienił się jednak stopień skomplikowania wyszukiwania stojącego za przeglądarką, a także różne źródła, które można teraz przeszukiwać. A9 pozwala na szukanie pojedynczego słowa w mediach takich, jak filmy, książki, strony Wiki, a także blogi. Na rysunku 1.3 zaprezentowano typowe wyniki, jakie zwróci wyszukiwarka po wpisaniu „Tour de France”.
Rysunek 1.3. Rezultat typowego wyszukiwania frazy „Tour de France”
Ajax pojawia się, kiedy zaznaczy się pola wyboru i doda bądź usunie źródło wyszukiwania. Można zaznaczyć na przykład wikipedia, a na stronie bez jej odświeżenia pojawi się dodatkowa ramka, nawet jeśli nie było jej w początkowym wyszukiwaniu. Można odznaczyć wybrane wcześniej kategorie, a odnalezione odnośniki znikną. Wszystko dzieje się natychmiast i jest w dużej mierze zgodne z duchem bogatego i współpracującego z użytkownikiem interfejsu.
Rozdział 1.
Wprowadzenie do Ajaksa
29
Google Suggest oraz Google Maps Google Suggest oraz Google Maps zostały wymienione w artykule z Adaptive Path jako dobre przykłady użycia Ajaksa. Tu jednak zostały omówione na końcu, ponieważ wykorzystanie Ajaksa nie jest w nich tak dominujące jak w przypadku aplikacji webowych przedstawionych wcześniej, a także dlatego, że jako przykłady są znane aż zbyt dobrze. Google Suggest jest wersją wyszukiwarki, która próbuje oferować sugestie wraz z wpisywaniem podobnego zapytania. Jak widać na rysunku 1.4, aplikację tę można znaleźć pod adresem www.google.com/webhp?complete=1&h1=en.
Rysunek 1.4. Google Suggest
Jedyne, co sprawia, że rekomendowanie tej strony ze względu na zastosowanie Ajaksa jest nieco wątpliwe, to fakt, iż listy z autouzupełnieniem mogą nie być dobrze widziane przez użytkowników. Mogą one bowiem być przez nich postrzegane jako nachalne bądź mylące. Użytkownicy wiadomości SMS w telefonach komórkowych doskonale znają uczucie frustracji spowodowane tym, że, na przykład, przyimek „w” jest pomocniczo zmieniany na „z” w trakcie wpisywania wiadomości. Jest to zasługą kodu odpowiedzialnego za „przewidywanie” tego, co wpisze użytkownik. W Google Suggest można znaleźć dobre zastosowanie tej techniki, jednak kiedy wykorzysta się coś podobnego w sprawdzaniu poprawności formularza, należy uważać, by nie wpłynęło to źle na jego używalność. Prosty komunikat o błędzie często wystarczy.
30
Ajax. Od podstaw Ajax wykorzystywany jest również w Google Maps. Kiedy wskazana zostanie jakaś lokalizacja na mapie, aplikacja ładuje odpowiedni jej fragment. Przy przewijaniu mapy, zamiast trzymać wszystkie obrazy w pamięci, mapa jest ładowana w blokach — wtedy, kiedy są one potrzebne. Działanie Google Maps można zobaczyć na rysunku 1.5. Ładowanie map jest faktycznie bardzo szybkie.
Rysunek 1.5. Google Maps
Jest to kolejny przykład wykorzystania tylko jednej techniki do poprawienia używalności strony internetowej dla użytkownika.
Inne strony internetowe Ajax wykorzystywany jest na wielu stronach internetowych i oczywiście niemożliwe jest przyjrzenie się im wszystkim. Dobrym pomysłem może być zajrzenie na listę dziesięciu najlepszych aplikacji opartych na Ajaksie A Venture Forth. Listę tę można znaleźć na stronie www.aventureforth.com/2005/09/06/top-10-ajax-applications/. Zawiera ona kalendarz internetowy, edytor tekstu, czytnik RSS, narzędzie do zarządzania projektami oraz wersję Google Suggest dla Amazon Suggest. Ten zbiór stanowi niezły przykład możliwości, z jakich można skorzystać. Ograniczeniem jest tylko własna wyobraźnia.
Rozdział 1.
Wprowadzenie do Ajaksa
31
Pod adresem http://swik.net/Ajax/Places+To+Use+Ajax znajduje się lista zadań, do jakich można wykorzystać Ajaksa na stronie internetowej. Ta strona ma format Wiki, jest zatem bardzo interaktywna, a użytkownicy stale dodają kolejne sugestie. Poniżej znajduje się lista kilku ciekawszych pomysłów.
Dynamiczne menu — strony stale się zmieniają, a konieczność narzucenia im ścisłej struktury oznacza coraz większą ilość pracy, w miarę jak struktura ta się zmienia. Menu działają lepiej, kiedy obsługuje je kod po stronie klienta, a dane potrzebne do ich wypełnienia mogą zostać pobrane za pomocą Ajaksa.
Autozapisywanie — dobrą procedurą działającą w tle może być automatyczne zapisywanie zawartości pola tekstowego bez pytania o to użytkownika.
Autouzupełnianie — przewidywanie fraz tekstu, jak w Google Suggest, o ile wykonane jest dobrze, może przyspieszyć proces wpisywania tekstu.
Podział na strony bądź organizowanie dużej liczby wyników — kiedy przez zapytanie, takie jak w wyszukiwarce, zwracane są duże ilości danych, aplikacja oparta na Ajaksie może pomóc w ich sortowaniu, organizowaniu oraz wyświetlaniu w rozsądnych częściach.
Komunikacja pomiędzy użytkownikami — każdy zapewne dwa razy by się zastanowił nad użyciem komunikatora takiego, jak Gadu-Gadu czy MSN Messenger, gdyby ekran odświeżał się za każdym razem, gdy wysyła się bądź odbiera wiadomość. Jednak w przypadku forum internetowego czy czatu w aplikacjach webowych często tak właśnie może być. Natychmiastowa komunikacja z innym użytkownikiem w aplikacji webowej jest dobrym sposobem na zastosowania Ajaksa.
Jak widać, wszystkie te zadania już teraz wykonywane są za pomocą technologii po stronie serwera. Mogłyby one jednak zostać wykonane lepiej, gdyby część z nich wykonywana była po stronie klienta, dzięki czemu strona internetowa byłaby szybsza i bardziej interaktywna.
Złe przykłady Oczywiście nie wszystkie przykłady zastosowania Ajaksa na stronach internetowych są dobre. Jak już wspomniano wcześniej, nie każdy obszar nadaje się do użycia Ajaksa. Do listy błędów związanych z wykorzystaniem Ajaksa — autorstwa Aleksa Boswortha (http:// alexbosworth.backpackit.com/pub/67688) —dodano notatkę o treści: „Używanie Ajaksa dla samego używania Ajaksa”2. Tym, co być może najbardziej irytuje przeciwników Ajaksa, jest fakt, iż programiści potrafią każdą modną technologię czy metodologię zastosować bez względu na jej przydatność w konkretnej sytuacji. Co zatem czyni wykorzystanie Ajaksa złym przypadkiem? Przedstawienie kilku adresów URL na pewno miałoby wartość demonstracyjną, byłoby też nieco zuchwałe, jednak zapewne wywołałoby sporo kontrowersji, nie wspominając o pozwach sądowych. Jest to także dość subiektywne. Lepiej będzie zatem zdefiniować „złe przykłady” jako takie strony wykorzystujące Ajaksa, które są wolniejsze w tym, co robią, niż gdyby to samo osiągnięto za pomocą przesłania danych do serwera. 2
Listę można również znaleźć na stronie Wiki: http://swik.net/Ajax/Ajax+Mistakes, gdzie użytkownicy mogą ją uzupełniać i rozwijać — przyp. tłum.
32
Ajax. Od podstaw Można się na przykład spotkać z aplikacją dzielącą na strony wyniki z wyszukiwarki, która, choć nie uaktualnia strony, zwraca wyniki wolniej, niż gdyby zapytanie przesłano po prostu do serwera. Problem polega na tym, że przenosząc akcent na klienta, w części uzależnia się działanie aplikacji od zasobów komputera użytkownika oraz jego przeglądarki. Jeśli da się im do przetworzenia duże ilości danych, procesor Pentium 2 nie przetworzy ich tak szybko, jak Pentium 4. Innym złym przykładem zastosowania Ajaksa będzie sprawdzanie poprawności formularza, w którym przerywa się wprowadzanie danych przez użytkownika, zanim skończy on je wpisywać. Nie należy przerywać normalnych wzorców zachowania użytkownika, który wpisuje czy wprowadza dane. Jednym z kluczowych celów Ajaksa powinno być ulepszenie interakcji użytkownika ze stroną. W niektórych przypadkach może to oznaczać, że zastosowanie Ajaksa będzie bardzo subtelne bądź prawie niezauważalne, jednak w przypadku interfejsów użytkownika jest to zaletą. Czas wyjaśnić, od czego pochodzi nazwa Ajax, i dlaczego to, co oznacza ta nazwa, niekoniecznie jest tym, do czego Ajax jest wykorzystywany obecnie.
Ajax — akronim Po lekturze artykułu z Adaptive Path wiadomo już, że akronim Ajax pochodzi od Asynchronous JavaScript and XML (po polsku: asynchroniczny JavaScript i XML). A teraz niespodzianka: Ajax nie musi używać XML i nie musi też koniecznie być asynchroniczny. Aplikacje oparte na Ajaksie mogą wykorzystywać XML i mogą być uaktualniane asynchronicznie. Są to dość popularne sztuczki i techniki wykorzystywane do uaktualniania strony, jednak nie są one niezbędną częścią tych technologii. By wrócić do wcześniej podnoszonej kwestii — Ajax jest „zbiorem technik programistycznych”, „pewnym podejściem do programowania webowego”. Nie ma jednak sztywnego podziału, to nie zamknięty klub, w którym, jeśli nie wykorzystuje się wszystkich technik, nie używa się Ajaksa. Ajax to ogólna filozofia programowania. Sposób osiągnięcia określonych celów zależny jest od programisty. Same cele są jednak dobrym punktem wyjścia. Jesse James Garrett wspomniał w swoim artykule o „kilku technologiach (…), które razem łączą się na nowe sposoby”. Poniżej znajduje się lista technologii, o których pisał:
XHTML oraz CSS,
DOM (Document Object Model),
JavaScript,
XML oraz XSLT,
obiekt XMLHttpRequest.
W rzeczywistości żeby utworzyć aplikację opartą na Ajaksie, potrzebne są jedynie trzy elementy — XHTML, DOM oraz JavaScript. Jeśli jednak wykorzystuje się programowanie w Ajaksie na dużą skalę, z pewnością w pewnym momencie konieczne będzie wykorzystanie wszystkich z wymienionych technologii.
Rozdział 1.
Wprowadzenie do Ajaksa
33
Prawdopodobnie będzie również potrzebny jakiś język po stronie serwera, który będzie odpowiedzialny za interakcję z serwerem. Najczęściej jest to jeden z trzech poniższych języków:
PHP,
ASP.NET (Visual Basic/C#),
Java.
Ktoś, kto buduje strony internetowe, z pewnością spotkał się z wieloma bądź z większością tych technologii, jednak być może nie ze wszystkimi, dlatego warto krótko przypomnieć, czym jest każda z nich i czym się zajmuje, a także jaką rolę spełnia w programowaniu strony internetowej oraz w jaki sposób odnosi się do Ajaksa.
XHTML oraz CSS Język HTML (HyperText Markup Language), lingua franca Internetu, z pewnością jest dobrze znany, jednak być może nie tak dobrze znany jest jego następca — XHTML (eXtensible HyperText Markup Language). XHTML jest bardziej wymagającą wersją HTML. Tak naprawdę jest to standard HTML określony jako dokument XML. Podstawowa różnica polega na tym, że podczas gdy HTML był dość pobłażliwy, a przeglądarki próbowały wyświetlić wszystko, co znajdowało się w znacznikach, XHTML przestrzega reguł XML. Dokumenty XML muszą być na przykład poprawne składniowo (ang. well-formed — oznacza to, że znaczniki muszą być poprawnie otwierane i zamykane, a także zagnieżdżane) — i tak samo jest w przypadku stron XHTML. Poniższe zagnieżdżenie jest na przykład poprawne:
To jest poprawnie zagnieżdżony znacznik H1.
Następujący przykład zagnieżdżenia będzie z kolei niepoprawny:
To jest niepoprawnie zagnieżdżony znacznik H1.
Choć może się to wydawać sprzeczne z pobłażliwą naturą łatwego do napisania HTML, jeśli strona nie będzie skonstruowana w poprawny sposób, nie będzie można wykorzystać Ajaksa omówionego w niniejszej książce. By móc korzystać z DOM, strona musi być poprawna składniowo. W innym przypadku nie będzie się dało uzyskać dostępu do różnych części strony. Kaskadowe arkusze stylów (CSS) to szablony stojące za stronami HTML, które opisują prezentację oraz ułożenie tekstu i danych zawartych w stronach HTML. CSS jest szczególnie interesujący dla programisty, ponieważ zmiany dokonane w arkuszach stylów są natychmiast widoczne na stronie. Arkusze stylów są połączone z dokumentem najczęściej za pomocą znacznika , choć możliwe jest (ale nie jest to zalecane) określenie atrybutów stylów dla każdego znacznika HTML na stronie z osobna. Do właściwości CSS można również uzyskać dostęp za pomocą DOM.
34
Ajax. Od podstaw Projektując stronę internetową bądź inną aplikację webową, powinno się dokonać podziału na zawartość (strukturę) strony i jej prezentację — na tyle, na ile jest to możliwe. Powiedzmy, że ma się sto stron i na wszystkich stu stronach określa się rozmiar czcionki w atrybucie style. Kiedy konieczna staje się zmiana wielkości czcionki, trzeba wprowadzić zmiany na każdej ze stron z osobna, zamiast zmienić tę właściwość tylko raz — w arkuszu stylu. Posiadanie arkusza stylów nie jest w stu procentach niezbędne, jednak do utrzymywania dobrej organizacji strony arkusze stylów są niezastąpione.
DOM (Document Object Model) DOM to reprezentacja stron internetowych w postaci hierarchii bądź struktury drzewa, w której każda część strony (grafika, pola tekstowe, przyciski oraz sam tekst) jest modelowana przez przeglądarkę. Przed przeglądarkami Internet Explorer 4 oraz Netscape Navigator 4 nie każda część strony była dostępna dla kodu. Tak naprawdę zmiana tekstu na stronie musiała być dokonywana za pomocą technologii po stronie serwera albo nie była wykonywana wcale. Cała strona została nazwana dokumentem, a dokument ten zawierał składające się na stronę znaczniki HTML oraz tekst. DOM określany jest jako standard przez konsorcjum World Wide Web, znane również jako W3C (www.w3.org), jest to zatem standardowy sposób reprezentowania stron przez wszystkie przeglądarki. Jest niemalże pewne, że kiedy wykorzysta się JavaScript do zmiany koloru tła w IE, tak samo poprawnie zostanie to wykonane w przeglądarkach takich, jak Mozilla, Safari bądź Opera. Istnieją jednak wyjątki od tej reguły. W Internet Explorerze istnieje kilka niestandardowych metod, a elementy takie, jak kontrolki ActiveX nie mogą być wykorzystywane w innych przeglądarkach. Możliwe jest dodawanie elementów do DOM bądź ich zmiana za pomocą języka skryptowego (takiego, jak JavaScript czy VBScript); na stronie pojawią się one natychmiast. Zazwyczaj odnosi się do nich w formacie, jaki odpowiada stronie w postaci hierarchicznej, jak na przykład w poniższym kodzie, w którym zmienia się tekst przycisku o nazwie button w formularzu. Warto zwrócić uwagę na to, iż w tym fragmencie kodu element formularza ma atrybut name ustawiony na form1: document.form1.button.value = "Kliknij mnie";
Można również wykorzystać metody, które uzyskują dostęp do określonych elementów czy też podzbiorów elementów na stronie, takie jak metoda document.getElementById, która zwraca określone wystąpienie elementu odpowiadające poniższym kryteriom: var myTextBox = document.getElementById(myTextbox);
Następnie można przypisywać wartości do zmiennych utworzonych w celu zmiany wartości. By pole tekstowe stało się niewidoczne, można wywołać następującą metodę: myTextBox.style.visibility = "visible";
Rozdział 1.
Wprowadzenie do Ajaksa
35
Inną powiązaną metodą jest getElementsByTagName. Metoda ta zwraca tablicę elementów strony internetowej typu NodeList, które mają określoną nazwę znacznika — nawet jeśli na stronie znajduje się tylko jedno wystąpienie tego elementu. Poniższy kod pozwala zwrócić wszystkie elementy obrazków ze strony: var imageElements = document.getElementsByTagName("img");
Możliwe jest również składanie strony poprzez dodawanie do dokumentu nowych części zwanych węzłami (ang. node). Mogą to być elementy, atrybuty bądź nawet zwykły tekst. Można na przykład utworzyć element span, zawierający krótką wiadomość, i dodać go do strony w następujący sposób: var newTag = document.createElement("span"); var newText = document.createTextNode("Tutaj znajduje się pewien nowy tekst. Ho ho!"); newTag.appendChild(newText); document.body.appendChild(newTag);
Wszystkie techniki DOM stosuje się po stronie klienta, w rezultacie czego przeglądarka może uaktualniać stronę bądź jej części natychmiast. Ajax w dużym stopniu polega na tych możliwościach, starając się zapewnić użytkownikom możliwie bogatą interakcję z aplikacjami. Jak wspomniano, techniki te istnieją od czasów przeglądarek Internet Explorer 4 oraz Netscape Navigator 4 — były jedynie aż do teraz niedoceniane. DOM jest ważną kwestią, dlatego bardziej szczegółowo zostanie omówiony w rozdziale 2.
JavaScript JavaScript jest językiem skryptowym wybieranym przez większość programistów webowych. Znajomość JavaScriptu jest też niezbędna do korzystania z niniejszej książki. W książce tej nie naucza się tego języka, w rozdziale 2. zamieszczono jednak krótkie przypomnienie najważniejszych kwestii z nim związanych. Ajax nie jest domeną JavaScriptu. VBScript oferuje te same możliwości dynamicznego uaktualniania, jednak połączone tylko z przeglądarką Internet Explorer. Choć standard dla JavaScriptu określony został w specyfikacji ECMAScriptu, JavaScript został stworzony w przeglądarce Netscape Navigator, zanim jeszcze powstały standardy. Microsoft utworzył równolegle własną wersję tego języka (pod nazwą JScript) i w rezultacie wersja JavaScriptu w każdej z przeglądarek jest nieco inna. Choć JavaScript pozostaje bardzo ważnym narzędziem uaktualniania stron internetowych, pewna ilość dublującego się kodu jest niezbędna do tego, by aplikacje i strony internetowe działały tak samo we wszystkich przeglądarkach. Kiedy jest to niemożliwe, niezbędne będzie również zastosowanie jakiegoś kodu obsługującego błędy. Spora ilość kodu w Ajaksie będzie miała na celu poradzenie sobie z różnicami pomiędzy przeglądarkami oraz generowanymi przez te różnice błędami, o ile nie można zagwarantować, że odbiorcy strony będą korzystać tylko z jednej przeglądarki (na przykład w lokalnym intranecie). Jest to nieszczęśliwy zbieg okoliczności, którego nawet najnowsze wersje przeglądarek Internet Explorer oraz Firefox nie potrafią naprawić. W późniejszych rozdziałach dylematy te zostaną omówione bardziej szczegółowo.
36
Ajax. Od podstaw
XML, XSLT oraz XPath Kolejnym znanym wszystkim programistom webowym kluczowym elementem Ajaksa jest XML, język wykorzystywany do opisu i strukturyzowania danych. Choć XML powiązany jest z całym mnóstwem dodatkowych technologii, każda z nich zajmuje swoją własną niszę. Dokument XML nie zawiera informacji o tym, w jaki sposób powinien być wyświetlany czy przeszukiwany. Po wygenerowaniu danych w formie dokumentu XML zazwyczaj trzeba skorzystać z innych technologii, by móc wyszukać w nim jakieś informacje bądź wyświetlić je. Przeglądarki Internet Explorer oraz Firefox zawierają silniki XML, które potrafią analizować składniowo dokumenty XML. XSLT jest językiem transformacji dokumentów XML w inne dokumenty XML. Nie jest jednak ograniczony do transformacji tego typu — jako format danych wyjściowych można również podać HTML bądź zwykły tekst. Kiedy dokonuje się transformacji dokumentu, rozpoczyna się od dokumentu źródłowego, takiego jak na przykład poniższy fragment:
Hotel Luksusowy 50 Katowice
Hotel Wygodny 500 Warszawa
Drugi dokument w XSLT stosuje się do pierwszego dokumentu. Dokument XSLT zawiera zbiór reguł określających, w jaki sposób powinna być wykonana transformacja:
Nazwa hotelu | Liczba pokoi | Lokalizacja |
| | |
Rozdział 1.
Wprowadzenie do Ajaksa
37
Otrzymuje się wynikowy dokument XML (w tym przypadku również dokument XHTML), który wygląda w następujący sposób:
Nazwa hotelu | Liczba pokoi | Lokalizacja |
Hotel Luksusowy | 50 | Katowice |
Hotel Wygodny | 500 | Warszawa |
Następnie można dynamicznie wstawić fragment dokumentu XHTML do strony HTML, by ją uaktualnić. XSLT jest kolejnym standardem utrzymywanym przez W3C. Zarówno Internet Explorer, jak i Mozilla posiadają procesory XSLT, nie zawsze jednak traktują one dokumenty XSLT w ten sam sposób. XSLT wykorzystuje jeszcze jeden język, XPath, do wykonywania zapytań do dokumentów XML, kiedy stosuje swoje transformacje. Zapytania XPath wykorzystywane są do odnoszenia się do elementów wewnątrz oryginalnego dokumentu XML, jak na przykład w poniższym kodzie:
Instrukcja //Hotel nakazuje procesorowi XSLT przeglądarki odszukanie elementów o nazwie będących potomkami elementu głównego . Zapytania XPath mogą być wykorzystywane do lokalizacji określonych elementów bądź grup elementów w ramach dokumentu XML za pomocą składni, która przypomina sposób odnajdywania stron internetowych w przeglądarce, jak w poniższym przykładzie: //HotelList/Hotel/Rooms
Techniki te można wykorzystać do pobierania części dokumentu z danymi i wyświetlania ich na stronie za pomocą przeglądarki. Ponownie są one w stanie zaoferować natychmiastowe uaktualnianie bez konieczności odwoływania się z powrotem do serwera. Zarówno XSLT, jak i XPath omówione są bardziej szczegółowo w rozdziale 8.
Obiekt XMLHttpRequest Jeśli w tej grupie technologii jest choć jedna, z którą Czytelnik raczej się nie spotkał, będzie to prawdopodobnie obiekt XMLHttpRequest. W przeglądarce Internet Explorer 5 Microsoft wprowadził niewielką kontrolkę ActiveX o nazwie obiektu XMLHTTP. Kontrolki ActiveX są oczywiście nierozerwalnie połączone z IE, dlatego niedługo potem inżynierowie z firmy Mozilla poszli w ślady Microsoftu i stworzyli własną wersję tego obiektu dla przeglądarek
38
Ajax. Od podstaw Mozilla 1 oraz Netscape 7, zwaną XMLHttpRequest. Status tych obiektów znacząco wzrósł z powodu uwzględnienia ich w artykule na temat Ajaksa z Adaptive Path. Teraz najczęściej określa się je mianem obiektu XMLHttpRequest, a w przeglądarce Internet Explorer 7 obok kontrolki ActiveX istnieje wbudowany obiekt XMLHttpRequest. Wersje tego obiektu znalazły się również w przeglądarkach Safari 1.2 oraz Opera. Jaką rolę pełni ten obiekt? Pozwala on programistom na przesyłanie oraz otrzymywanie obiektów XML w tle. Wcześniej do wykonania tego zadania można było wykorzystać ukryte ramki bądź ramki typu IFrame, jednak obiekt XMLHttpRequest jest bardziej wyszukany, jeśli chodzi o sposoby przesyłania oraz pobierania danych. Niestety, ponieważ nie jest on jeszcze standardem, istnieją dwa różne sposoby tworzenia go. W wersjach Internet Explorera poprzedzających wersję 7. obiekt ten tworzy się jako ActiveXObject w JavaScripcie, jak poniżej: var xHRObject = new ActiveXObject("Microsoft.XMLHTTP");
Istnieje wiele wersji biblioteki MSXML z odpowiednimi ProgID do tworzenia obiektów XMLHTTP. Nie można utworzyć obiektu XMLHTTP wyższego od Msxml2.XMLHTTP.3.0 dla danego, niezależnego od wersji ProgIDMicrosoft.XMLHTTP. Dla potrzeb niniejszej książki będzie to jednak wystarczające.
W przeglądarkach Mozilla Firefox, Internet Explorer 7, a także pozostałych, obiekt ten tworzony jest w następujący sposób: var xHRObject = new XMLHttpRequest();
Oznacza to z kolei, że przed ustaleniem tego, z której wersji tworzenia obiektu należy skorzystać, trzeba będzie sprawdzić, z jaką przeglądarką ma się do czynienia. Ponieważ kontrolki i obiekty ActiveX są unikalne dla Internet Explorera, można sprawdzić ich istnienie za pomocą próby wywołania metody ActiveXObject obiektu window. W przeglądarkach Internet Explorer 7, Mozilla Firefox, Safari oraz Opera istnieje metoda XMLHttpRequest. Te wywołania wykorzystują niejawną konwersję typów w celu zwrócenia true bądź false w zależności od tego, jaka przeglądarka wykorzystywana jest do wyświetlenia strony. Innymi słowy, jeśli w przeglądarce tej istnieje metoda ActiveXObject, zwrócona zostanie wartość true. Jeśli tak nie będzie, zwrócona będzie wartość false. Zazwyczaj kod wykrywający używaną przeglądarkę oraz sposób tworzenia obiektu wygląda mniej więcej tak: var xHRObject = false; if (window.XMLHttpRequest) { xHRObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); } else { // Wykonanie jakiegoś działania w przeglądarkach nieobsługujących Ajaksa. }
Rozdział 1.
Wprowadzenie do Ajaksa
39
Istnieją plany, by ustandaryzować tę funkcjonalność w specyfikacji DOM Level 3, jednak do tego czasu trzeba będzie uwzględnić istniejące rozbieżności w swoich programach. Obiekt XMLHttpRequest pełni bardzo ważną rolę. Wykorzystywany jest na dużą skalę w aplikacji Gmail firmy Google, gdzie służy do pobierania i przesyłania danych w tle. Tak naprawdę w aplikacjach opartych na Ajaksie obiekt ten może być odpowiedzialny za część asynchroniczną. Wykorzystuje zdarzenie onreadystatechange do wskazania, kiedy zakończył ładowanie informacji. Można mu nakazać pobranie dokumentu XML, jak w poniższym kodzie: xHRObject.open("GET", "SuiteList.xml", true);
Później można sprawdzić wartość właściwości readyState, aby przekonać się, czy pobieranie zostało zakończone, a jeśli tak — aby pobrać potrzebne informacje. Obiekt XMLHttpRequest jest nieco mylący z tego powodu, że nie trzeba za jego pomocą przesyłać kodu w formacie XML. Można go również z powodzeniem wykorzystać do transferu HTML czy po prostu zwykłego tekstu. Obiekt XMLHttpRequest jest omówiony nieco bardziej szczegółowo w rozdziale 4. Różnica pomiędzy synchronicznymi a asynchronicznymi metodami transferu danych przedstawiona zostanie w dalszej części rozdziału.
Technologie po stronie serwera Ostatnią częścią równania (i jednocześnie tą, która nie została w zasadzie ujęta w artykule Jesse Jamesa Garretta) są technologie po stronie serwera, z jakich będzie musiał skorzystać Ajax. W niniejszej książce wykorzystano PHP oraz ASP.NET (w odpowiednich miejscach) w celu obsłużenia żądań skierowanych do serwera. Żadna z metod nie jest lepsza od innych. Powinno się raczej używać tej, którą się najlepiej zna. Tak jak w przypadku JavaScriptu, w książce tej nie naucza się używania PHP czy ASP.NET. Oczekuje się raczej, że Czytelnik zna już jedną z tych technologii. Technologie po stronie serwera omówione są w rozdziale 3., w bieżącym rozdziale staramy się unikać zbyt szczegółowego ich przedstawiania, ponieważ stanowią one raczej spoiwo dla Ajaksa, a nie jego kręgosłup. Skoro wszystkie części Ajaksa są już na swoim miejscu, czas przyjrzeć się bliżej temu, w jaki sposób Ajax zmienia tradycyjny sposób interakcji w Internecie.
Model aplikacji opartej na Ajaksie Początkowo Internet służył do wyświetlania jedynie dokumentów HTML. Oznaczało to, że klasyczna aplikacja webowa reprezentowała model „wprowadź dane, prześlij stronę do serwera, poczekaj na odpowiedź”, zaplanowany jedynie dla stron internetowych. Po drugie, istniał problem komunikacji synchronicznej. Dobrym przykładem rzeczywistego urządzenia synchronicznego jest publiczna budka telefoniczna. By komunikacja mogła się odbyć, trzeba do kogoś zadzwonić, a osoba ta musi być dostępna. Mając wiele budek telefonicznych,
40
Ajax. Od podstaw nie można liczyć na to, że rozmówca oddzwoni do nas. Można jedynie samemu do niego zadzwonić i dzielić się informacjami. Po rozmowie należy opuścić budkę, gdyż często w kolejce czekają inne osoby, które chcą z niej skorzystać. Jeśli rozmówca nie podał nam odpowiednich informacji — mamy pecha. Przykładem komunikacji asynchronicznej będzie telefon domowy, za pomocą którego dzwoni się do kogoś. Rozmówca nie może podać nam pożądanych informacji od razu, ale zgadza się oddzwonić, kiedy będzie je miał, bez względu na to, kiedy się to stanie. W Internecie synchroniczność oznacza, że użytkownik wykorzystuje stronę HTML, a przeglądarka przesyła żądanie HTTP do serwera WWW w jego imieniu (rysunek 1.6). Serwer przetwarza dane, a następnie zwraca odpowiedź do przeglądarki w formie strony HTML. Przeglądarka wyświetla żądaną stronę HTML. To przeglądarka zawsze inicjuje żądania, podczas gdy serwer tylko na nie odpowiada. Serwer WWW nigdy nie inicjuje żądań — komunikacja zawsze jest jednostronna. Cykl „żądanie-odpowiedź” jest synchroniczny, a użytkownik musi czekać.
Rysunek 1.6. Model synchroniczny
Jak wspomniano, ten model działa dla stron internetowych, jednak rozwój coraz bardziej skomplikowanych aplikacji webowych oznacza, że model ten obecnie się załamuje. Pierwszym obszarem, w którym następuje owo załamanie, jest wydajność. Podejście „wprowadź dane, prześlij, czekaj” oznacza, że marnuje się wiele czasu. Po drugie, za każdym razem, gdy odświeża się stronę, nowe żądanie jest przesyłane z powrotem do serwera. Konieczne jest dodatkowe przetwarzanie po stronie serwera, co prowadzi do straty czasu związanej z oczekiwaniem na odpowiedź, a także wyższym zużyciem łącza spowodowanym niepotrzebnym odświeżaniem strony. Problemem jest tu całkowity brak dwustronnej komunikacji w czasie rzeczywistym — a serwer nie ma możliwości inicjowania uaktualnień.
Rozdział 1.
Wprowadzenie do Ajaksa
41
Ta sytuacja prowadzi do małej prędkości oraz niskiej wydajności aplikacji webowych. Występują tu dwa podstawowe problemy — konieczność oczekiwania na odpowiedź z serwera oraz niemożność inicjowania uaktualnień przez serwer. Model aplikacji opartej na Ajaksie stara się osiągnąć większą wydajność, tworząc tym samym lepsze aplikacje webowe i zmieniając nieco sposób ich działania. Ajax wprowadza do modelu aplikacji webowej pomysł „częściowego uaktualnienia strony”. W aplikacjach opartych na Ajaksie uaktualnione zostaną jedynie elementy interfejsu użytkownika, które zawierają nowe informacje. Pozostała część interfejsu użytkownika pozostanie bez zmian. Oznacza to, że nie trzeba przesyłać takiej ilości informacji, a także że nie ma konieczności oczekiwania na odpowiedź, ponieważ poprzednia strona działa. Ten model pozwala na ciągłe działania na stronie internetowej i oznacza również, że praca wykonywana na stronie nie musi odbywać się zgodnie z prostym, przewidywalnym wzorcem. Zamiast modelu synchronicznego można teraz stosować albo model asynchroniczny, albo model odpytywania (ang. polling). W aplikacji opartej na Ajaksie serwer może pozostawić powiadomienie, gdy będzie gotowy, natomiast klient podejmie je wtedy, gdy będzie miał na to ochotę. Klient może również odpytywać serwer w regularnych odstępach czasu, by przekonać się, czy ten jest już gotowy, jednak w międzyczasie może również kontynuować inne działania, co widać na rysunku 1.7. Rysunek 1.7. Model aplikacji opartej na Ajaksie
W rezultacie użytkownik może kontynuować wykorzystywanie aplikacji, w czasie gdy klient żąda odpowiedzi z serwera w tle. Kiedy nowe dane wreszcie się pojawią, wystarczy uaktualnić odpowiednie części interfejsu użytkownika.
Dlaczego powinno się używać Ajaksa? Omówiono już sam model, jednak warto zastanowić się, jakie są rzeczywiste zalety używania Ajaksa w aplikacjach.
Częściowe uaktualnianie strony Nie trzeba uaktualniać danych na całej stronie internetowej. Można uaktualnić tylko te części strony, które tego wymagają. Oznacza to, że nie będzie pełnego odświeżenia strony, do przesłania będzie mniejsza ilość danych, a interakcja z użytkownikiem zostanie poprawiona. Nie trzeba zacinać się ze strony na stronę.
42
Ajax. Od podstaw
Niewidoczne pobieranie danych Im dłużej ogląda się stronę, tym większa szansa, że przestanie być ona aktualna. Aplikacja oparta na Ajaksie, choć z zewnątrz wygląda tak, jakby nic jej nie kazało niczego wykonywać, może się sama uaktualniać w tle.
Ciągłe uaktualnianie Ponieważ nie czeka się za każdym razem na uaktualnienie strony, a także dlatego, że Ajax potrafi pobierać dane w tle, aplikacje mogą być ciągle uaktualniane. Tradycyjne programy, takie jak Word czy Outlook, zmieniają wyświetlane menu czy pokazywane widoki w zależności od konfiguracji, przechowywanych danych czy też okoliczności, w jakich funkcjonują. Nie muszą czekać na serwer czy użytkownika, który wykona jakieś działanie, zanim pobiorą nowy e-mail czy zastosują nowy szablon. Ajax pozwala aplikacjom webowym zachowywać się podobnie do aplikacji desktopowych.
Jednolite interfejsy Interfejs, który nie musi być zmieniany, jest automatycznie interfejsem użytkownika, który będzie łatwiejszy w użyciu. Ajax może tutaj działać na dwa sposoby, umożliwiając modyfikację części interfejsu, a także zwyczajnie myląc użytkowników i powodując, że tracą oni grunt pod nogami. Teoretycznie, dokonując niewielkich zmian, można wspomóc przejście użytkownika przez interfejs i przyspieszyć cały proces.
Prostota i bogactwo możliwości Jak pokazały poprzednie przykłady, niektóre z robiących największe wrażenie aplikacji opartych na Ajaksie są jednocześnie tymi, w których najbardziej trzeba się Ajaksa naszukać, jak w Basecamp. Jeśli Ajax może zostać wykorzystany tak, by aplikacja została uproszczona, a jednocześnie ulepszona z punktu widzenia użytkownika, to faktycznie jest to poprawa.
Przeciąganie i upuszczanie Przeciąganie i upuszczanie (ang. drag and drop) jest jedną z najpowszechniejszych technik stosowanych w większości aplikacji, od Eksploratora Windows po pulpit. Nie zalicza się ona do możliwości stricte ajaksowych. To coś, co w aplikacjach webowych było możliwe już od wielu lat, nawet przed wprowadzeniem obiektu XMLHttpRequest. Większość programistów wybierała jednak technologię Flash czy podobne rozbudowane rozwiązanie, zamiast korzystać z rozwiązań opartych na JavaScripcie oraz DOM. Według ponownej oceny technik tworzenia interfejsu użytkownika sprowokowanej przez Ajaksa przeciąganie i upuszczanie może być wykorzystywane w dokonywaniu zmian, które następnie zostaną przesłane do serwera za pomocą Ajaksa. Można na przykład przeciągnąć kilka elementów na ekranie na nowe pozycje, a następnie wylogować się. Kiedy powróci się później na stronę, elementy te powinny się znajdować w tych samych miejscach.
Rozdział 1.
Wprowadzenie do Ajaksa
43
Znając tyle zalet Ajaksa, trudno sobie odpowiedzieć na pytanie, dlaczego nie każdy programista przechodzi na używanie aplikacji ajaksowych. Z pewnością istnieją jednak pewne przeszkody, które należy wziąć pod uwagę.
Kiedy nie należy używać Ajaksa Po opanowaniu technik Ajaksa nie powinno się wracać do swoich starych stron i tworzyć ich zupełnie od nowa. Zamiast tego powinno się raczej rozważyć, w jaki sposób można poprawić używalność stron, a także zastanowić się nad tym, czy Ajax jest rozwiązaniem, które je ulepszy. Jeśli nie będzie istotnej poprawy, równie dobrze można nie robić nic. Sporo artykułów tłumaczy, dlaczego nie powinno się wykorzystywać Ajaksa w pewnych okolicznościach; są to na przykład teksty, które można znaleźć pod następującymi adresami:
Ajax sucks — http://www.usabilityviews.com/ajaxsucks.html (parodia artykułu Jakoba Nielsena na temat tego, czemu ramki są beznadziejne),
Ajax, promise or hype — http://www.quirksmode.org/blog/archives/2005/03/ajax_promise_or.html,
Ajax is not cool — http://www.lastcraft.com/blog/index.php?p=19.
Spowolnienie strony Prawdopodobnie najbardziej rzucającym się w oczy problemem związanym z Ajaksem jest to, że choć w teorii technologia ta wykorzystywana jest do przyspieszenia interakcji, tak naprawdę jednak spowalnia stronę. Jeśli stale wykorzystuje się Ajaksa do przesyłania danych do serwera, okazuje się, że strona staje się wolniejsza. Ewentualnie jeśli serwer zwraca do klienta duże zbiory danych, może się okazać, że przeglądarka będzie się męczyła z ich obsługą na czas. Teoretycznie wyszukiwarka może się wydawać dobrym miejscem do zastosowania Ajaksa w celu podzielenia danych, by nie trzeba było odświeżać strony, kiedy przechodzi się od wyników 1 – 10 do wyników 11 – 20. W rzeczywistości jednak o wiele lepsze będzie wykorzystanie do tego serwera — zamiast nakazywać przeglądarce, by spróbowała sobie poradzić ze zbiorem danych mającym ponad 1000 rekordów. Inteligentne i rozsądne stosowanie Ajaksa jest tu kluczowe.
Zakłócenie działania przycisku Wstecz w przeglądarce Aplikacje oparte na Ajaksie, o ile nie używa się ich w sposób rozumny, mogą zakłócić działanie przycisku Wstecz w przeglądarce. Jeden z najlepszych przykładów aplikacji opartych na Ajaksie — Gmail — używa przycisków Wstecz oraz Dalej (lub Do przodu) w sposób bardzo efektywny. Istnieje również mnóstwo stron, które nie wykorzystują Ajaksa, a i tak wyłączają działanie przycisku Wstecz. Na naszej liście wykroczeń ta kwestia nie ma zatem zbyt wysokiej pozycji w hierarchii.
44
Ajax. Od podstaw
Zakłócanie działania zakładek oraz blokowanie indeksów wyszukiwarek Jeśli w aplikacji opartej na Ajaksie doda się stronę do zakładek (lub tak zwanych „Ulubionych”), może się okazać, że na liście tej znajdzie się inna strona. JavaScript tworzy określony widok strony, który nie ma wiele wspólnego z oryginalnym adresem URL. Jeśli mamy dynamiczny system menu, może się wydawać, że wystarczy usunąć część strony z menu, by była ona niedostępna, jednak w rzeczywistości wiele osób nadal może ją oglądać. Mnóstwo stron otrzymuje w ten sposób tysiące wywołań ich starych wersji, które powodują tylko błędy na serwerze. Możliwe jest tworzenie aplikacji webowych, które dobrze sobie radzą z zakładkami oraz przyciskami Wstecz. Dobry przykład opisu radzenia sobie z obydwoma problemami w efektywny sposób można znaleźć na stronie http://onjava.com/lpt/a/6293.
Obciążenie dla przeglądarki Jeśli przeniesie się cały ciężar przetwarzania danych na przeglądarkę, w większym stopniu polega się właśnie na niej oraz na komputerze użytkownika, który odpowiedzialny jest za przetwarzanie. Oczekiwanie na to, aż przeglądarka przetworzy stronę, nie jest w niczym lepsze od oczekiwania na to, aż serwer odeśle odpowiedź. Tak naprawdę w niektórych przypadkach może nawet być gorsze, jeśli przeglądarką tą będzie Internet Explorer, który zdecyduje się „skonsumować” wszystkie dostępne zasoby na komputerze w czasie przetwarzania danych, dzięki czemu komputer będzie odpowiadał w żółwim tempie. W tym momencie Czytelnik zastanawia się zapewne nad tym, czy skoro wszystkie powyższe zastrzeżenia są uzasadnione, to Ajax może faktycznie obniżyć używalność aplikacji. Jeśli podejdzie się do tych problemów rozważnie i zaradzi się kłopotom związanym z przyciskiem Wstecz oraz zakładkami, to nie istnieje powód, dla którego nie można by było skorzystać z Ajaksa. Pojawia się jednak pewne pytanie. Skoro artykuł Jesse Jamesa Garretta miał tyle wad, dlaczego stał się on tak popularny? Być może dlatego, że autor wyartykułował kwestie, o których wiele osób myślało, i opisał rozwiązania, które wiele osób stosowało, jednak nie było dla nich nazwy. To, że w sposobach wykonywania było nieco nieścisłości, nie miało znaczenia. Garrett dotknął czułej struny programistów. Sytuację tę można porównać to do niektórych wczesnych utworów grupy The Beatles, które nie były najlepiej zagrane, ale są wspominane z rozrzewnieniem, ponieważ przebijały się przez nie znajome rytmy. Nawet programiści, którym coś w artykule nie odpowiadało, zgadzali się z tym, że opisywał on rozsądne podejście do tworzenia aplikacji webowych, a także z tym, że powrócił on do starych, zapomnianych bądź ignorowanych technik.
Kto może bądź nie może używać Ajaksa? Nie trzeba chyba mówić, że nie każdy będzie w stanie używać Ajaksa. Zawsze powinno się zwracać uwagę na części strony, które mogą wykluczać niektórych użytkowników poprzez zastosowanie określonej technologii; powinno się też rozważyć, w jaki sposób zwrócić się do tej części publiczności docelowej.
Rozdział 1.
Wprowadzenie do Ajaksa
45
Poniżej znajdują się najważniejsze kwestie, jakie należy wziąć pod uwagę.
Użytkownicy relatywnie nowych wersji najważniejszych przeglądarek (Internet Explorer 4+, Mozilla Firefox/Netscape 7+, Safari, Opera 5+) mogą z powodzeniem wykorzystywać aplikacje oparte na Ajaksie. Użytkownicy starszych wersji przeglądarek nie będą w stanie tego zrobić.
Osoby, które mają wyłączoną obsługę języków skryptowych, nie będą w stanie używać Ajaksa (ani aplikacji opartych na JavaScripcie). Zanim będzie się z tego drwiło, warto przypomnieć sobie, że po niedawnym odkryciu luk zarówno w Internet Explorerze, jak i w programie Microsoft Outlook firma Microsoft zalecała wyłączenie obsługi skryptów do czasu, gdy luki te zostaną załatane.
Ludzie przeglądają aplikacje offline. Może się to wydawać prehistorycznym sposobem korzystania z Internetu, ale w pewien sposób jest to również metoda bardzo nowoczesna. Na przykład w komunikacji za pośrednictwem telefonów komórkowych przepustowość łącza jest o wiele mniejsza, a koszty wyższe, dlatego często zdarza się, że użytkownicy logują się, pobierają coś, a następnie wylogowują się. Strony takie, jak AvantGo pozwalają na przeglądanie offline wybranych stron internetowych. Gdyby na stronach tych znajdował się Ajax, przestałyby one działać.
I znów trzeba wiedzieć, kim jest publiczność docelowa, a także znać jej potrzeby.
Stwórz swój własny przykład Nie powinno się zakończyć czytania tego rozdziału z uczuciem „to po co w ogóle używać Ajaksa?”. Nie taki jest cel. Istnieją czas i miejsce na właściwe wykorzystywanie Ajaksa. Można użyć tu porównania z szybkim samochodem. Pewnie jest on w stanie osiągnąć prędkość stu kilometrów na godzinę w siedem sekund, a także jechać z szybkością dwustu pięćdziesięciu kilometrów na godzinę. Jednak miasto czy zwykła droga nie są miejscem do prezentowania tych możliwości. Można się narazić na niezadowolenie pozostałych uczestników ruchu, nie wspominając już o policji. Tak samo jest z Ajaksem. Jeśli używa się go przy każdej dostępnej okazji, być może okaże się, że strona nie ma aż tylu odwiedzających, jak wyobrażał sobie to jej autor. Tworzenie aplikacji opartej na Ajaksie polega na dobrym zaprojektowaniu i przemyśleniu tego, w jaki sposób interfejs użytkownika skorzysta na zastosowaniu Ajaksa. Poniżej zademonstrowano krótki przykład pokazujący, w jaki sposób można wykorzystać obiekt XMLHttpRequest oraz pliki XML do utworzenia dynamicznego systemu menu dla określonego scenariusza biznesowego. A scenariusz ten jest następujący. Mamy biuro podróży, na którego stronie internetowej wyświetlane są informacje dotyczące hoteli oraz apartamentów. Informacje te publikowane są jako plik XML. Często zdarza się, że firmy publikują dane jako tekst bądź jako pliki XML w tym samym miejscu w określonych odstępach czasu, ponieważ zazwyczaj mogą one być wygenerowane automatycznie. Przykład ten pokazuje nie tyle narzędzie służące do publikowania pliku XML, a raczej pobieranie nowych danych z określonego miejsca co
46
Ajax. Od podstaw dziesięć sekund. Spowoduje to z kolei uaktualnianie opcji z systemu menu bez konieczności odświeżenia strony. Przykład ten jest dość złożony. Prezentuje wymowny sposób używania Ajaksa. Warto przejrzeć kod aplikacji. W kolejnych rozdziałach omówione zostaną: obiekt XMLHttpRequest, wykorzystanie DOM, a także scenariusze, w których w aplikacjach można wykorzystać XML oraz XSLT.
spróbuj sam Pierwszy przykład w Ajaksie 1.
Należy utworzyć nowy folder w katalogu głównym serwera WWW o nazwie BegAjax. Wewnątrz niego należy utworzyć folder o nazwie r01.
2. Trzeba rozpocząć od utworzenia pliku XML. Należy zapisać go jako SuiteList.xml
w folderze r01.Warto zwrócić uwagę na to, iż pliki te można tworzyć w Notatniku bądź preferowanym edytorze tekstowym. Jeśli nie chce się wpisywać całego kodu ręcznie, można go pobrać z serwera FTP pod adresem: ftp://ftp.helion.pl/przyklady/ajaodp.zip.
1001 Wenecja 2 150 10
1002 Werona 2 90 10
1003 Neapol 2 180.00 10
1003 Rodzinny 6 270.00 10
3. Następnie trzeba utworzyć skrypt w JavaScripcie, który będzie odpowiedzialny
za przetwarzanie po stronie klienta. Należy go zapisać jako ajax.js w tym samym folderze — r01.
Rozdział 1.
Wprowadzenie do Ajaksa
// Utworzenie obiektu XMLHttpRequest var xHRObject = false; if (window.XMLHttpRequest) { xHRObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData() { // Sprawdzenie czy obiekt XMLHttpRequest jest gotowy i czy zwrócił on poprawną odpowiedź if (xHRObject.readyState == 4 && xHRObject.status == 200) { var xmlDoc = xHRObject.responseXML; if (window.ActiveXObject) { // Załadowanie XSL var xsl = new ActiveXObject("Microsoft.XMLDOM"); xsl.async = false; xsl.load("MenuDisplay.xsl"); // Transformacja var transform = xmlDoc.transformNode(xsl); var spanb = document.getElementById("menuhere"); } else { var xsltProcessor = new XSLTProcessor(); // Załadowanie XSL XObject = new XMLHttpRequest(); XObject.open("GET", "MenuDisplay.xsl", false); XObject.send(null); xslStylesheet = XObject.responseXML; xsltProcessor.importStylesheet(xslStylesheet); // Transformacja var fragment = xsltProcessor.transformToFragment(xmlDoc, document); document.getElementById("menuhere").innerHTML = ""; document.getElementById("menuhere").appendChild(fragment); } // Wyświetlenie wyników transformacji if (spanb != null) { spanb.innerHTML = transform; } // Wyczyszczenie obiektu i wywołanie funkcji getDocument za 10 sekund xHRObject.abort(); setTimeout("getDocument()", 10000); } }
47
48
Ajax. Od podstaw function getDocument() { // Przywrócenie funkcji do stanu początkowego xHRObject.onreadystatechange = getData; // Internet Explorer przechowa żądanie GET w pamięci podręcznej. Jedynym sposobem // obejścia tego jest dodanie jakiegoś łańcucha znaków zapytania. W tym przypadku // dodaje się nową datę jako łańcuch znaków zapytania. xHRObject.open("GET", "SuiteList.xml?id=" + Number(new Date), true); xHRObject.send(null); }
4. W tym przykładzie potrzebny będzie również arkusz stylów XSL. Odpowiedzialny
jest on za prezentację danych zawartych w dokumencie XML. Będzie to część kontrolująca to, które elementy z dokumentu XML będą wyświetlane, a które nie. Arkusz stylów XSL powinien zostać zapisany jako MenuDisplay.xsl w folderze r01.
5. Następnie potrzebny będzie arkusz stylów CSS, który kontroluje włączanie
i wyłączanie dynamicznych podmenu oraz prezentację bloków menu, na przykład ich kolory oraz rozmiar czcionki. Plik SuiteListStyles.css powinien zostać zapisany w folderze r01. td.menublock { background-color: #eeeeff; width: 120px; height: 25px; border-style: ridge; border-width: thin; border-color: gray; font-weight: bold; text-align: center; font-family: Arial; color: gray; } div.submenublock { visibility: hidden; background-color: lightsteelblue; position: absolute; top: 70px; left: 133px; width: 180px; border-style: ridge; border-width: thin;
49
50
Ajax. Od podstaw color: gray; font-weight: bold; text-align: center; font-family: Arial; } a { color: white; text-decoration: none; } a:hover { background-color: #28618E; font-weight: bold; }
6. Na końcu znajduje się strona HTML, która zawiera bardzo niewiele szczegółów.
Posiada po prostu odnośniki do skryptu oraz arkusza CSS, a także pojedynczy element
, do którego zapisuje się informacje z menu. Plik ten powinien zostać zapisany jako dafault.htm w folderze r01.
Pierwszy przykład w Ajaksie
7. Należy otworzyć przeglądarkę i wyświetlić stronę default.htm. Należy się upewnić,
że robi się to za pośrednictwem serwera WWW. Na przykład wpisanie do paska adresu przeglądarki następującego adresu będzie poprawne: http://localhost/BegAjax/r01/default.htm
Gdyby jednak przejść bezpośrednio do pliku za pośrednictwem Eksploratora Windows i kliknąć go, okazałoby się, że (w przeglądarce Internet Explorer) pokazałby się następujący adres, który by nie działał: C:\InetPub\BegAjax\r01\default.htm
Tak jak technologie po stronie serwera, obiekt XMLHttpRequest wymaga, by serwer pracował poprawnie. Jeśli tak jest, można zobaczyć stronę z pięcioma opcjami menu po lewej stronie. Cztery z tych opcji są nieaktywne. Aktywna jest tylko opcja Hotel Rzym, a jeśli przesunie się nad nią wskaźnik myszy, pojawi się niebieskie menu (rysunek 1.8).
Rozdział 1.
Wprowadzenie do Ajaksa
51
Rysunek 1.8. Przesunięcie wskaźnika myszy nad aktywną opcję Hotel Rzym
8. Teraz coś ciekawego. Powiedzmy, że wykorzystywany dokument XML właśnie
został uaktualniony, tak by odzwierciedlał fakt, iż apartament Wenecja nie będzie dostępny. Należy powrócić do pliku SuiteList.xml i zmienić liczbę tygodni dla tego apartamentu na 0: ...
1001 Wenecja 2 150 0
...
9. Teraz należy powrócić do strony, nie odświeżając jej jednak. Trzeba poczekać
jakieś dziesięć – piętnaście sekund. Należy raz jeszcze przesunąć wskaźnik myszy nad Hotel Rzym, jak pokazano na rysunku 1.9. 10. Górny wpis zniknął.
Jak to działa Jak wspomniano wcześniej, szczegóły tego rozwiązania nie zostaną omówione teraz, gdyż zastosowane techniki przedstawione zostaną w kolejnych rozdziałach. Zamiast tego warto przyjrzeć się temu, co robi aplikacja i w jaki sposób różne jej części są do siebie dopasowane. Utworzono tu prosty system menu w szablonie XSL. Składa się on z tabeli z pięcioma wierszami. Szablon XSL pobiera dane z dokumentu XML SuiteList.xml. Środkowy wiersz szablonu XSL zawiera zdarzenie JavaScriptu onmouseover, które włącza widoczność podmenu. Szablon XSL zawiera podszablon wykorzystywany do wyświetlania tego podmenu:
52
Ajax. Od podstaw
Rysunek 1.9. Nowy rezultat przesunięcia wskaźnika myszy nad Hotel Rzym
Instrukcje XSL wykorzystywane są w tym szablonie do wykonania iteracji po dokumencie SuiteList.xml. Instrukcja xsl:for-each lokalizuje każdy element w dokumencie XML. W sumie istnieją cztery takie elementy: ...
1001 Wenecja 2 150 0
...
Następnie instrukcja wykorzystywana jest do warunkowego wyświetlenia elementu podmenu. Sprawdzana jest wartość elementu i jeśli jest ona większa od zera, wyświetlane są elementy oraz . Jeśli wartość ta nie jest większa od zera, nie
Rozdział 1.
Wprowadzenie do Ajaksa
53
dzieje się tak. W rezultacie w podmenu pokazują się tylko te apartamenty, których wartość WeeksFree jest większa od zera, co odpowiada wymaganiom biznesowym, by wyświetlać tylko te apartamenty, które są wolne. Najbardziej interesujące jest jednak to, co dzieje się w tle. Zamiast czekać na powrót do serwera i odświeżenie strony, kod ładuje dokument XML ponownie co dziesięć sekund. Wszystko to kontrolowane jest w kodzie JavaScriptu dla tej strony. W czterech krótkich krokach tworzy się obiekt XMLHttpRequest, ustawia się powiadomienie, kiedy załadowany zostanie dokument XML, pobiera się dokument XML i przesyła go. Tworzenie obiektu XMLHttpRequest wykonywane jest na początku kodu. Jest ono niezależne od przeglądarki, jednak można tu dodać nieco kodu, by upewnić się, że zadziała również w programie Internet Explorer 6. Obiekt ten tworzy się na początku, by był on dostępny dla wszystkich funkcji ze skryptu. // Utworzenie obiektu XMLHttpRequest var xHRObject = false; if (window.XMLHttpRequest) { xHRObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); }
Pozostałe trzy kroki mieszczą się w funkcji getDocument(), która jest ładowana na początku strony za pomocą programu obsługi zdarzeń onload elementu body: // Przywrócenie funkcji do stanu początkowego xHRObject.onreadystatechange = getData; // Internet Explorer przechowa żądanie GET w pamięci podręcznej. Jedynym sposobem obejścia // tego jest dodanie jakiegoś łańcucha znaków zapytania. W tym przypadku dodaje się nową datę // jako łańcuch znaków zapytania. xHRObject.open("GET", "SuiteList.xml?id=" + Number(new Date), true); xHRObject.send(null);
Kiedy zdarzenie readystatechange zostaje uruchomione, wywołuje funkcję getData. Funkcja ta sprawdza, czy odpowiedź (XML) została zwrócona z serwera, i podejmuje działanie tylko wtedy, jeśli tak było. Wykonuje następnie trzy kroki mające na celu załadowanie dokumentu XML z danymi, załadowanie arkusza stylów XSL (kontrolującego, które części danych są wyświetlane w menu) oraz wykonanie transformacji na dokumencie XML — co oznacza, że te dwa dokumenty połączone zostaną ze sobą, tak by utworzyć fragment dokumentu HTML: if (window.ActiveXObject) { // Załadowanie XSL var xsl = new ActiveXObject("Microsoft.XMLDOM"); xsl.async = false; xsl.load("MenuDisplay.xsl"); // Transformacja var transform = xmlDoc.transformNode(xsl); var spanb = document.getElementById("menuhere"); } else
54
Ajax. Od podstaw { var xsltProcessor = new XSLTProcessor(); // Załadowanie XSL XObject = new XMLHttpRequest(); XObject.open("GET", "MenuDisplay.xsl", false); XObject.send(null); xslStylesheet = XObject.responseXML; xsltProcessor.importStylesheet(xslStylesheet); // Transformacja var fragment = xsltProcessor.transformToFragment(xmlDoc, document); document.getElementById("menuhere").innerHTML = ""; document.getElementById("menuhere").appendChild(fragment); }
XSLT jest specyficzny dla danej przeglądarki, dlatego w kodzie znajduje się osobna część dla Internet Explorera, a osobna dla Firefoksa, jednak obie robią to samo. Przechowują odpowiedź XML, ładują arkusz stylów XSL i wykonują transformację. Fragment jest następnie wstawiany do strony w elemencie o identyfikatorze menuhere. Kiedy zostanie dokonana zmiana w dokumencie, nie trzeba już polegać na odświeżaniu strony. Dokument XML jest ładowany, a następnie umieszczany w DOM za pomocą właściwości innerHTML. spanb.innerHTML = transform;
Na koniec czyści się obiekt XMLHttpRequest za pomocą metody abort, a następnie wykorzystuje setTimeout do wywołania kolejnej funkcji getDocument(). Wykonuje ona to samo przetwarzanie obiektu XMLHttpRequest, jakie wykonano na początku skryptu, i generalnie ustawia cykl, który ładuje dokument XML co dziesięć sekund. // Wyczyszczenie obiektu i wywołanie funkcji getDocument za 10 sekund xHRObject.abort(); setTimeout("getDocument()", 10000);
Ponowne ładowanie strony co dziesięć sekund zdecydowanie nie jest najbardziej wydajnym sposobem wypełniania dynamicznego menu. Można rozważyć pewne alternatywy. ASP.NET posiada obiekt Cache, który pozwala na utworzenie zależności w taki sposób, by, kiedy plik XML będzie uaktualniany, zawartość pamięci podręcznej była automatycznie odświeżana. To rozwiązanie można dopasować do tej aplikacji w taki sposób, by menu uaktualniane było za każdym razem, gdy uaktualniony zostanie plik; będzie on załadowany ponownie do obiektu XMLHttpRequest. Obecnie, w takim kodzie, jaki zaprezentowany został powyżej, gdyby ładowano duży plik XML co dziesięć sekund, mogłoby się to skończyć brakiem odpowiedzi, czego chcieliśmy uniknąć. Przykład ten służy jednak tylko do zademonstrowania tego, w jaki sposób działają takie uaktualnienia. Wszystko odbywa się następująco. Dane zawarte są w dokumencie XML, a do interpretacji tego dokumentu wykorzystywany jest arkusz stylów XSL. Można użyć DOM oraz XMLHttpRequest do załadowania połączonego dokumentu XML-XSL do strony HTML co dziesięć sekund. Arkusz stylów CSS wykorzystany został do wyświetlenia danych wyjściowych w nieco bardziej reprezentacyjny sposób. Jeśli Czytelnik ma uczucie, że wszystkiego jest trochę za dużo, nie powinien się przejmować. Każdy aspekt zostanie omówiony z osobna w którymś z kolejnych rozdziałów. Na razie należy wiedzieć, że istnieje model, w którym można uaktualniać część strony internetowej
Rozdział 1.
Wprowadzenie do Ajaksa
55
bez konieczności jej odświeżania — i bez opóźnienia. Warto również zauważyć, że jest to tylko jedno z wielu możliwych zastosowań Ajaksa. W niniejszej książce omówionych zostanie mnóstwo innych technik wykorzystujących Ajaksa w zupełnie odmienny sposób.
Podsumowanie Niniejszy rozdział poświęcony został omówieniu tego, czym jest Ajax, a także powodom, dla których można używać Ajaksa. Opisano artykuł Jesse Jamesa Garretta, a także wiele komponentów, które Garrett wymieniał jako składające się na aplikację opartą na Ajaksie. Ponieważ pojawiło się wiele teorii oraz sporów na temat tego, co jest aplikacją opartą na Ajaksie, a co nią nie jest, w rozdziale tym wyjaśniono, że nie wszystkie elementy wymienione w artykule można znaleźć w każdej aplikacji ajaksowej. Omówienie to wyjaśnia, w jaki sposób bezkrytyczne i nierozważne stosowanie Ajaksa może mieć efekt odwrotny od zamierzonego. W przykładach pokazano działanie kilku dobrych aplikacji opartych na Ajaksie wraz z technikami w nich zastosowanymi. Na koniec Czytelnik utworzył własną aplikację, która wykorzystuje wiele z technologii omówionych i wykorzystywanych w niniejszej książce.
Ćwiczenia Sugerowane odpowiedzi na poniższe pytania znajdują się w dodatku A. 1.
Jakie elementy definiują aplikację webową jako aplikację opartą na Ajaksie?
2. Dlaczego nazwa Ajax może być uznawana za mylący akronim?
56
Ajax. Od podstaw
2
Powtórka z JavaScriptu JavaScript jest ważnym elementem pakietu Ajaksa. Służy on jako pośrednik między przeglądarką (klientem) a serwerem, by strona mogła być dynamicznie uaktualniana bez odświeżania jej w całości. JavaScript został stworzony przez Brendana Eicha i wprowadzony w wydaniu przeglądarki Netscape 2.0 w 1995 roku. Ponieważ JavaScript oferował możliwość dodawania interaktywności do stron HTML, szybko stał się bardzo popularny i szeroko stosowany. Różne wersje tego języka były rozwijane zarówno przez firmę Netscape, jak i przez innych producentów przeglądarek, aż w końcu JavaScript został ustandaryzowany przez ECMA (European Computer Manufacturers Association, obecnie ECMA International) jako ECMAScript. Standard ECMAScriptu definiuje jądro języka JavaScript. Większość dzisiejszych przeglądarek obsługuje trzecie wydanie standardu ECMA-262. W niniejszym rozdziale znajduje się przegląd jądra JavaScriptu (ECMAScriptu), obiektów JavaScriptu, DOM oraz obsługi zdarzeń — przeznaczony raczej dla Czytelników, którzy mają już pewne doświadczenie z JavaScriptem i podstawowymi konstrukcjami w programowaniu (zmiennymi, operatorami, funkcjami). Jeśli Czytelnik dopiero zaczyna programować bądź poznawać JavaScript, warto zajrzeć do książek takich, jak JavaScript. Wprowadzenie (Helion, 2007) czy JavaScript dla webmasterów. Zaawansowane programowanie (Helion, 2006) w celu uzyskania bardziej szczegółowych informacji na temat tego języka. W niniejszym rozdziale omówione zostaną następujące zagadnienia:
jądro JavaScriptu (zmienne, operatory, instrukcje, funkcje),
JavaScript zorientowany obiektowo (obiekty wbudowane, BOM, obiekty definiowane przez użytkownika),
DOM (Document Object Model),
JavaScript oraz zdarzenia.
58
Ajax. Od podstaw
Jądro JavaScriptu Jądro JavaScriptu (ECMAScript) dostarcza wszystko to, co potrzebne jest do wykonania podstawowych zadań programistycznych: zmienne, operatory działające na tych zmiennych, instrukcje oraz funkcje, które udostępniają bloki kodu nadające się do ponownego użycia. Obiekty są również częścią ECMAScriptu i omówione są w dalszej części niniejszego rozdziału, w podrozdziale „JavaScript zorientowany obiektowo”.
Składnia Standard ECMAScript określa podstawowe reguły składni JavaScriptu. Używanie poprawnej składni jest bardzo istotne. Jeśli kod ma błędy składniowe, interpreter JavaScriptu z przeglądarki przestanie przetwarzać kod, dopóki błąd nie zostanie poprawiony. Poniższe wskazówki pomogą przestrzegać dobrych praktyk w programowaniu i unikać błędów składniowych.
W JavaScripcie wielkość liter ma znaczenie. Należy szczególnie uważać, kiedy używa się dużych liter w nazwach zmiennych, funkcji oraz obiektów. Zmienna o nazwie myVar to nie to samo, co zmienna myvar.
Średniki są opcjonalne. Choć nie jest wymagane umieszczanie średników na końcu każdej instrukcji kodu, dobrą praktyką jest umieszczanie ich tam w celu oznaczenia, gdzie kończy się wiersz. Sprawia to, że kod łatwiej się czyta oraz łatwiej usuwa się z niego błędy. Końcowe średniki pomagają również zmniejszyć liczbę błędów wygenerowanych podczas czytania kodu przez przeglądarkę.
Należy pozwolić na zawijanie kodu. Nie należy wstawiać znaków nowych wierszy w środku wiersza kodu. Wstawienie znaku nowego wiersza w środku instrukcji jest jednym z najczęściej popełnianych błędów w JavaScripcie, a nowe wiersze mogą sprawić, że kod będzie niefunkcjonalny.
Dodawanie komentarzy. Składnia dla komentarzy to // dla komentarzy mieszczących się w jednym wierszu i /* oraz */ dla komentarzy rozciągających się na kilka wierszy. Komentowanie kodu sprawia, że o wiele łatwiej jest zrozumieć go w czasie, gdy jest on uaktualniany bądź usuwane są z niego błędy. Należy pamiętać, że osobą wykonującą te czynności niekoniecznie musi być pierwotny autor kodu.
Zmienne Zmienna (ang. variable) jest tymczasowym pojemnikiem służącym do przechowywania danych. Zmienne w JavaScripcie można deklarować poprzez użycie słowa kluczowego var. Poniższy kod deklaruje na przykład nową zmienną o nazwie myColor: var myColor;
Rozdział 2.
Powtórka z JavaScriptu
59
Ta zmienna nie zawiera jeszcze żadnych informacji. Gdyby umieścić ją w komunikacie z ostrzeżeniem typu alert, takim jak poniższy, jej wartość byłaby równa undefined, co widać na rysunku 2.1: alert ("myColor = " + myColor);
Rysunek 2.1. Niezdefiniowana zmienna
Nie trzeba deklarować zmiennej w osobnym kroku. Zamiast tego można ją zainicjalizować — to znaczy zadeklarować ją i jednocześnie przypisać do niej jakąś wartość, jak w poniższym kodzie: var myColor = "green";
Nie jest konieczne używanie operatora var do deklarowania czy inicjalizowania zmiennych. Jeśli się ten operator pominie, zmienna automatycznie otrzyma zakres globalny. Używanie var podkreśla jednak, że deklaruje się czy też inicjalizuje nową zmienną, i ułatwia późniejszy proces usuwania błędów.
Nazwy zmiennych muszą rozpoczynać się od litery, znaku _ bądź $. W nazwach zmiennych często używana jest notacja zwana camelCase1, choć nie jest to wymagane. W zapisie tego typu pierwsza litera jest mała, natomiast dodatkowe słowa rozpoczynają się od dużej litery, jak poniżej: var myFavouriteNumber;
Podstawowe typy danych Każda zmienna JavaScriptu ma określony typ danych, który wskazuje na rodzaj danych, jakie zawiera ta zmienna. Podstawowe typy danych przechowują dane bezpośrednio w zmiennej. Istnieje pięć rodzajów podstawowych typów danych:
1
liczba,
łańcuch znaków,
wartość typu Boolean,
wartość typu Undefined (niezdefiniowana),
wartość typu Null (pusta).
Notacja camelCase, zwana czasem bikapitalizacją, to sposób zapisu pojęć złożonych polegający na bezpośrednim łączeniu wyrazów napisanych wielką literą (przy czym pierwsza litera całości często jest mała) bez używania spacji między nimi. Inna teoria głosi, że pojęcie to pochodzi od skojarzenia wielkich liter znajdujących się w środku wyrazu z wielbłądzimi garbami („camel” — ang. wielbłąd) — przyp. tłum.
60
Ajax. Od podstaw Typ liczbowy obejmuje zarówno liczby całkowite, jak i zmiennoprzecinkowe. Typ łańcuchów znaków obejmuje dowolną grupę składającą się z jednego bądź większej liczby znaków. Łańcuch znaków można odróżnić od liczby dzięki temu, że znajduje się on w cudzysłowie. Przykładowo "5" to łańcuch znaków, natomiast 5 — liczba. Typ Boolean ma dwie wartości — true bądź false. Typ Undefined (niezdefiniowany) posiada tylko jedną wartość — undefined. Typ Null (pusty) również posiada tylko jedną wartość — null. Wartość null oznacza, że obiekt nie istnieje. Nie trzeba określać typu danych, kiedy w JavaScripcie deklaruje się bądź inicjalizuje zmienną. JavaScript korzysta z typów dynamicznych — typ danych jest wnioskowany na podstawie kontekstu instrukcji JavaScriptu. Oznacza to również, że ta sama zmienna może być wykorzystana dla różnych typów danych w różnych momentach, jak widać w poniższym fragmencie kodu: var myNumer = "szczęśliwa"; // Zmienna myNumber zawiera łańcuch znaków myNumber = 3; // Zmienna myNumber zawiera liczbę
Referencyjne typy danych Referencyjne typy danych w JavaScripcie zawierają odniesienie (referencję) do miejsca w pamięci, które przechowuje dane, a nie same dane. Typ Object (jak również specjalne kategorie tego typu, takie jak Array czy Function) jest typem referencyjnym. Ważne, by jasno określić, czy używa się typu prostego, czy referencyjnego. Jeśli używa się typu referencyjnego jako parametru funkcji, a następnie wprowadzi się zmiany do danych wewnątrz tej funkcji, można zmodyfikować oryginalne dane w typie referencyjnym. Nawet jeśli zmiana wprowadzona jest lokalnie (wewnątrz funkcji), dane zmieniane są globalnie, jak widać w poniższym fragmencie kodu: function myArray(a) { var a[0] = 5; } var nextArray = [1, 2, 3]; myArray(nextArray); alert ("nextArray = " + nextArray);
Po wywołaniu funkcji myArray wartość nextArray równa jest 5,2,3.
Operatory Operatory pozwalają na wykonanie działania na zmiennej. Podstawowe operatory JavaScriptu obejmują operatory przypisania, arytmetyczne, porównania, logiczne oraz inkrementacji i dekrementacji.
Rozdział 2.
Powtórka z JavaScriptu
61
Operator przypisania Operator przypisania (=, ang. assignment operator) wykorzystywany jest do przypisywania wartości do zmiennej, jak w poniższym kodzie: var myTree = "dąb";
W tym przypadku wartość "dąb" przypisywana jest do zmiennej myTree.
Operatory arytmetyczne JavaScript zawiera operatory dla wszystkich podstawowych działań arytmetycznych, w tym dodawania (+), odejmowania (-), mnożenia (*) oraz dzielenia (/). Operator dodawania oraz operator konkatenacji łańcuchów znaków są tym samym znakiem, +. Jeśli używa się tego operatora z wartościami liczbowymi, liczby te są do siebie dodawane. Jeśli wykorzysta się go z łańcuchami znaków, łańcuchy te są ze sobą łączone (w procesie konkatenacji) w jeden łańcuch znaków. var a = 5; var b = 10; var c = a + b; // c = 15 a = "Moje"; b = " imię"; c = a + b; // c = "Moje imię"
JavaScript zawiera również operator reszty (ang. remainder operator, modulus operator), %. Operator ten wykorzystywany jest do obliczania wartości reszty z dzielenia liczby przez inną liczbę, jak widać w poniższym przykładzie: var myMod = 16%5; // myMod = 1
Wykorzystywanie reszty z dzielenia jest prostym sposobem sprawdzenia, czy liczba całkowita jest parzysta, czy nieparzysta. Wystarczy obliczyć integer%2. Jeśli wynikiem będzie 0, liczba jest parzysta.
Operatory porównania Operatory porównania (ang. comparison operators) wykorzystywane są do analizowania wyrażenia i zwracania wartości typu Boolean (true bądź false) wskazującej, czy porównanie było prawdą, czy fałszem. Jeśli na przykład a = 2, a b = 4, to wyrażenie a > b zwróci false. Operatorem porównania jest w tym przypadku operator „większy niż”, >. W tabeli 2.1 zaprezentowano operatory porównania JavaScriptu.
62
Ajax. Od podstaw
Tabela 2.1. Operatory porównania w JavaScripcie Operator
Znaczenie
>
Większy niż
=
Większy niż bądź równy
createElement('root'); $root = $doc->appendChild('root'); $child = $doc->createElement('child'); $child = $root->appendChild($child); $value = $doc->createTextNode("Dane"); $value = $child->appendChild($value); $strXml = $doc->saveXML(); echo $strXml;
W ten sposób powstanie następujący dokument XML:
Dane
Łańcuch znaków dołączany jest do odpowiedzi HTTP i odsyłany z powrotem do klienta jako gotowy do pobrania. Choć ta część procesu jest prosta, kiedy odpowiedź wraca do klienta, pobranie danych jest nieco bardziej skomplikowane.
Obiekt XMLHttpRequest Jak zostanie to zaprezentowane w rozdziale 4., obiekt XMLHttpRequest nie jest jedyną metodą, którą ma się do dyspozycji w wykonywaniu interakcji pomiędzy klientem a serwerem w aplikacjach opartych na Ajaksie. Jest jednak metodą najczęściej używaną. W niniejszym rozdziale nie omówiono szczegółów działania tego obiektu, dlatego najlepiej będzie go sobie wyobrazić jako kolejną czarną skrzynkę, która oczekuje na dane wejściowe z odpowiedzi HTTP.
98
Ajax. Od podstaw
Funkcja zwrotna Pierwszy krok otrzymywania danych znany jest pod nazwą funkcji zwrotnej (ang. callback function). Jest to po prostu funkcja JavaScriptu, która wykonywana jest, kiedy dane zostaną w całości pobrane z serwera. Można jej nadać dość ogólną nazwę, taką jak na przykład getData(), a funkcja ta będzie w większości aplikacji opartych na Ajaksie wyglądała dość podobnie. Wewnątrz funkcji zwrotnej pierwszym zadaniem do wykonania jest sprawdzenie, czy dane są gotowe do pobrania. Wykonuje się to za pomocą sprawdzenia, czy właściwość readyState obiektu XMLHttpRequest równa jest 4 (wartość ta oznacza ukończenie). Na razie typowa funkcja zwrotna będzie wyglądała następująco: function getData() { if (xHRObject.readystate == 4) { // Tu następuje przetwarzanie } }
Po upewnieniu się, że dane są gotowe, można je pobrać za pomocą jednej z dwóch właściwości obiektu XMLHttpRequest:
responseText,
responseXML.
Właściwość responseText Wykorzystywanie właściwości responseText jest najczęściej stosowanym podejściem do pobierania danych z odpowiedzi HTTP; jest również najłatwiejszym rozwiązaniem. Można utworzyć nową zmienną JavaScriptu, która przechowa zawartość odpowiedzi i zwróci ją jako łańcuch znaków: var text = xHRObject.responseText;
Jeśli na stronie w ASP.NET utworzy się poniższy kod, wtedy właściwość responseText dla data będzie zawierała tekst To są nasze dane.: string data = "To są nasze dane."; Response.Write(data);
W PHP należy zrobić to w następujący sposób: $data = "To są nasze dane."; echo $data
I to wszystko. Można również pobrać w ten sposób kod HTML bądź XHTML. Co się jednak stanie, gdy chce się pobrać dane XML? Nadal można użyć metody responseText, zwróci ona jednak dane XML w postaci łańcucha znaków. Można zastanowić się nad poniższym kodem w ASP.NET: string data = "Dane"; Response.Write(data);
Rozdział 3.
Ajax oraz technologie po stronie serwera
99
W PHP będzie to wyglądało następująco: $data = "Dane"; echo $data
Powyższe fragmenty kodu zwrócą następujące dane: Dane
Zwracanie dokumentów XML w postaci łańcuchów znaków może jednak zniwelować wiele zalet korzystania z XML. Dlatego też istnieje właściwość responseXML.
Właściwość responseXML Właściwość responseXML na pierwszy rzut oka wygląda, jakby lepiej nadawała się do sytuacji, w których chce się przekazywać z powrotem do klienta dokumenty XML. Pozwala ona traktować odpowiedź jako obiekt dokumentu XML i wykonywać iteracje po różnych elementach, atrybutach oraz węzłach tekstowych za pomocą DOM. Jak to jednak zwykle bywa w przypadku Ajaksa, trzeba sobie zdawać sprawę z istnienia kilku problemów związanych z korzystaniem z tej właściwości. Powiedzmy, że mamy następujący kod po stronie serwera, który wczytuje dokument XML: string data = "Dane"; Response.Write(data);
A kod w JavaScripcie zmieni się na następujący: var text = xHRObject.responseXML;
Jeśli oczekuje się, że z powrotem otrzyma się w pełni działający dokument XML, to można się srogo zawieść. Z powrotem otrzyma się obiekt, jednak będzie on pusty, bez śladu po kodzie XML, jaki się przesyłało. Dzieje się tak, ponieważ ContentType odpowiedzi Response musi być ustawiony na text/xml przed wypisaniem odpowiedzi. string data = "Dane"; Response.ContentType = "text/xml"; Response.Write(data);
Niestety, Internet Explorer szczególnie źle to toleruje. Jeśli nie ustawi się tego dobrze na serwerze, nie będzie można wykorzystywać responseXML w tej przeglądarce. W przeglądarce Firefox możliwe jest użycie w JavaScripcie metody overrideMimeType przed wywołaniem kodu, dzięki czemu można nadpisać i ustawić typ zawartości na text/xml po stronie klienta, jak w poniższym kodzie: xHRObject.overrideMimeType("text/xml"); xHRObject.send(null); var document = xHRObject.responseXML;
100
Ajax. Od podstaw Metody tej nie ma jednak w przeglądarce Internet Explorer. Problemy nie kończą się jednak na tym. Jeśli popełni się błąd w dokumencie XML, tak że nie jest on poprawny składniowo, w IE otrzyma się ponownie pusty obiekt bez oczywistego komunikatu o błędzie.
Usuwanie błędów z responseXML Przy ustalaniu przyczyny otrzymywania pustego obiektu z responseXML można użyć czterech metod. Pierwsza polega na sprawdzeniu, czy dane są zwracane w responseText. Można na przykład wykorzystać do tego okno dialogowe z ostrzeżeniem typu alert, jak poniżej: var text = xHRObject.responseText; alert(text);
Można oczekiwać, że zobaczy się coś takiego, jak poniżej: Dane
Jeśli tak nie jest, oznacza to, że odpowiedź nie została poprawnie przesłana przez serwer i należy sprawdzić kod po stronie serwera. Wysoce prawdopodobne jest jednak, że dane te są poprawne. Jeśli dane nie są poprawne, kolejnym krokiem będzie sprawdzenie kodu błędu.
Usuwanie błędów z responseXML w przeglądarce Internet Explorer By odnaleźć więcej informacji na temat błędu w przeglądarce Internet Explorer, należy skorzystać z poniższego kodu, by móc uzyskać nieco bardziej szczegółowy komunikat o błędzie oraz radę na temat tego, co należy poprawić w dokumencie XML: var errorcode = xHRObject.responseXML.parseError.errorCode;
W normalnej sytuacji kod zwracany z przeglądarki Internet Explorer powinien być równy zero. Jednak, co bardziej prawdopodobne, jeśli ContentType na pewno jest ustawiony na text/xml, a responseXML.xml jest pusty, wtedy kod ten będzie inny niż zero. Dalsze informacje na temat znaczenia kodu zwracanego z właściwości responseXML można uzyskać w następujący sposób: var errormessage = xHRObject.responseXML.parseError.reason;
Usuwanie błędów z responseXML w przeglądarce Firefox Choć w przeglądarce Firefox nie ma odpowiednika obiektu parseError, w menu Narzędzia można znaleźć opcję Konsola błędów, która pozwala na przejrzenie znaczących komunikatów o błędzie obejmujących typ obiektu powodujący wystąpienie błędu. Jeśli w odpowiedzi istnieje problem z formatowaniem XML, konsola udostępni informacje takie, jak poniższe, i nie wymaga to żadnych zmian w kodzie w JavaScripcie ani też dodawania do niego czegokolwiek:
Rozdział 3.
Ajax oraz technologie po stronie serwera
101
Błąd: niepasujący znacznik. Oczekiwano: . Plik źródłowy: http://localhost:8080/Company/WebPages/framed.jsf?com.asparity.AJAX_CLIENT_ID= _idJsp0%3AmasterTree&com.company.AJAX_REQUEST=true&oracle.adf.faces.STATE_TOKEN=3& nodeString=%3A%3AdomainModel%3A1&clientNodeId=%3A%3AdomainModel%3A1%3Aawaiting AjaxData Wiersz: 1, Kolumna: 6905 Kod źródłowy: [...]
Dodatkowo istnieje również łatwy do zainstalowania dodatek Firebug1, który pozwala programistom badać ruch XHR w czasie rzeczywistym — zarówno żądania, jak i odpowiedzi.
Wykorzystywanie danych Po zwróceniu danych z właściwości responseXML można je pobrać tak, jakby były obiektem DOM. Załóżmy na przykład, że mamy następujący dokument:
Ajax. Od podstaw. 1
Można zwrócić element z dokumentu XML w następujący sposób: var XMLDoc = xHRObject.responseXML; var book = XMLDoc.getElementsByTagName("book");
Można również przejść do pierwszego elementu zawartego w w następujący sposób: var title = book[0].firstChild;
Istnieje znacząca różnica pomiędzy dwoma najważniejszymi przeglądarkami (Internet Explorer oraz Mozilla) w kwestii tego, w jaki sposób zawartość tekstowa zwracana jest z dokumentów XML. W Internet Explorerze zawartość tekstowa zwracana jest za pomocą właściwości text, jak w poniższym kodzie: var title = book[0].firstChild.text; // Tytuł będzie równy "Ajax. Od podstaw."
W przeglądarkach Mozilla zawartość tekstową zwraca się za pomocą właściwości textContent, co widać w poniższym fragmencie kodu: var title = book[1].firstChild.textContent; // Tytuł będzie równy "Ajax. Od podstaw."
1
Firebug, a także inne narzędzia i sposoby usuwania błędów z aplikacji, omówione są w rozdziale 6. — przyp. tłum.
102
Ajax. Od podstaw Nietrudno również zauważyć, że w Internet Explorerze do pierwszego węzła odnosi się przez book[0], natomiast w przypadku przeglądarki Firefox jest to book[1]. Dzieje się tak, ponieważ w Firefoksie book[0] zawiera węzeł tekstowy ze znakiem nowego wiersza, gdyż przeglądarka ta nie opuszcza białych znaków (ang. whitespace) — traktuje je jak osobne węzły, podczas gdy Internet Explorer tego nie robi. I znów niezbędne jest uwzględnienie tych różnic w kodzie, by dostęp do danych zwracanych z serwera działał we wszystkich przeglądarkach.
Technologie po stronie serwera Dotychczas wspomniano jedynie o procesie, w którym dane mogą być przesyłane do serwera i odsyłane z niego; nie omawiano tego, co dzieje się na samym serwerze. Technologie po stronie serwera to zagadnienie niezależne od Ajaksa, dlatego trzeba się tych kwestii uczyć osobno. Załóżmy zatem, że Czytelnik posiada już praktyczną znajomość jednej z tych technologii, ponieważ bez umiejętności wykonywania przetwarzania na serwerze daleko się nie zajdzie. Poniżej znajduje się krótkie wprowadzenie do każdej z wybranych technologii wraz z prostą przykładową aplikacją opartą na Ajaksie, która z nich korzysta. Jeśli Czytelnik jest zaznajomiony z ASP.NET, ale z PHP czy Javą już nie, nie powinien pomijać podrozdziałów poświęconych tym ostatnim językom. Znajomość innych języków czy technologii poza tymi, które już się dobrze zna, daje programiście nie tylko dobre podstawy, ale także zabezpieczenie na przyszłość. Często można spotkać kontrakty czy zlecenia, które obejmują przeniesienie aplikacji z jednego języka na drugi, co wymaga dobrej znajomości obu. Klasyczny ASP oraz PHP są do siebie dość podobne i wkrótce ich podobieństwo zostanie zaprezentowane. W poniższym omówieniu zostanie krótko wspomniana Java, by pokazać, w jaki sposób zgrabnie łączy się ona z filozofią Ajaksa. Na początek jednak pora na aktualny sztandarowy produkt firmy Microsoft — ASP.NET.
ASP.NET ASP.NET to technologia firmy Microsoft służąca tworzeniu dynamicznych stron internetowych. By mogła działać na komputerze, konieczne jest spełnienie dwóch warunków: zainstalowanie platformy .NET Framework oraz posiadanie kompatybilnego serwera WWW, najczęściej IIS (Internet Information Services). .NET istnieje od 2002 roku, jednak aktualne większe wydanie (.NET 3.0) zostało opublikowane w listopadzie 2006 roku. Najnowszą wersję można pobrać ze strony http://update. microsoft.com. Należy wybrać opcję Instalacja niestandardowa, a nie Instalacja ekspresowa, i szukać w Oprogramowanie opcjonalne. Serwer IIS jest z kolei dostępny tylko jako część systemu operacyjnego Windows. W wielu wersjach systemu Windows domyślnie nie jest on zainstalowany i tym samym nie jest dostępny w Windows XP Home Edition. Można go jednak dodać, przechodząc do Panelu sterowania i wybierając Dodaj lub usuń programy, a później Dodaj/Usuń składniki systemu Windows.
Rozdział 3.
Ajax oraz technologie po stronie serwera
103
ASP.NET ma być niezależny od języka programowania. Pomysł polega na tym, że można używać implementacji dowolnego języka w .NET, w którym tworzy się aplikacje. Zazwyczaj sprowadza się to do wyboru pomiędzy dwoma językami programowania — Visual Basic oraz C#. W tej książce przykłady w ASP.NET tworzone będą w języku C#, ponieważ jest on podobny do JavaScriptu, jeśli chodzi o strukturę oraz opcje, takie jak znaczenie wielkości liter. Język ten jest również bardziej zbliżony do PHP. By uruchomić aplikację w ASP.NET, należy umieścić ją w folderze C:\inetpub\wwwroot\ nazwa_aplikacji (czy też dowolnym innym miejscu wybranym dla aplikacji), a następnie użyć serwera IIS do utworzenia wirtualnego katalogu. Można to zrobić poprzez uruchomienie IIS i kliknięcie prawym przyciskiem myszy katalogu, jaki chce się uruchomić, a następnie wybranie jego Właściwości, co widać na rysunku 3.4.
Rysunek 3.4. Wybieranie właściwości katalogu w IIS
Następnie w oknie dialogowym, które się pokaże, należy kliknąć przycisk Utwórz, dzięki czemu tworzy się nową aplikację (jak widać na rysunku 3.5). Później w przeglądarce przechodzi się do nowej aplikacji (w tym przypadku do http://localhost/ BegAjax/r03), po czym otrzymuje się Błąd HTTP 403 — Dostęp zabroniony, który oznacza, że udało się utworzyć katalog. Po poprawnym umieszczeniu aplikacji na serwerze WWW wywołuje się ją z JavaScriptu dzięki odniesieniu się do strony ASP.NET, jaką chce się wywołać, za pomocą metody Open obiektu XMLHttpRequest, jak poniżej: XMLHttpRequestObject.open("POST", "response.aspx?value=1", "true");
104
Ajax. Od podstaw
Rysunek 3.5. Przycisk Utwórz w oknie dialogowym Właściwości
Przykład wykorzystujący Ajaksa oraz ASP.NET Utwórzmy fikcyjną stronę z katalogiem dla sprzedawcy książek wraz z koszykiem na zakupy. Pozwoli to użytkownikowi na umieszczanie wybranych przedmiotów w koszyku z zakupami i uaktualnianie tego koszyka bez konieczności odświeżania strony. Załóżmy, że użytkownik został już zidentyfikowany, by strona mogła być tak prosta, jak to tylko możliwe. Koszyk z zakupami będzie miał trzy opcje:
można do niego dodawać przedmioty,
jeśli doda się do niego kolejny przedmiot, liczba przedmiotów wzrośnie o jeden,
można z niego usuwać przedmioty.
Oczywiście nie jest to coś, co można osiągnąć całkowicie po stronie klienta, choć po stronie klienta wszystko można zainicjować. Aplikacja odczyta tytuł książki ze strony klienta i przekaże go do serwera. Jest to wykorzystywane przy identyfikacji książki, kiedy umieszcza się ją w koszyku z zakupami. Na serwerze koszyk z zakupami musi śledzić, jakie przedmioty umieścił w nim użytkownik, a także jaka jest ich liczba. By móc tego dokonać, koszyk zostanie przechowany w zmiennej sesji. Oznacza to, że w dużym katalogu użytkownik będzie mógł przechodzić ze strony do strony bez tracenia informacji o tym, co zostało umieszczone w koszyku. Do przechowania informacji w koszyku z zakupami można wykorzystać dokument XML. Istnieje tylko jeden element koszyka, a wewnątrz niego znajduje się element książki dla każdego tytułu, jaki kupuje użytkownik. Element książki zawiera elementy tytułu oraz liczby
Rozdział 3.
Ajax oraz technologie po stronie serwera
105
egzemplarzy (choć można oczywiście dodać numer ISBN, cenę oraz autorów). Choć ma się tylko jedną stronę katalogu, przykład ten jest skalowalny, więc powinno się go dać uruchomić na wielu stronach z katalogami produktów.
spróbuj sam Przykład z koszykiem z zakupami w ASP.NET 1.
Należy utworzyć nowy plik o nazwie Catalogue.htm.
Książka:Ajax. Zaawansowane programowanie
Autor: Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett
ISBN: 978-83-246-0567-5
Cena: 67.00
Dodaj do koszyka
2. Należy utworzyć skrypt o nazwie Cart.js. var xHRObject = false; if (window.XMLHttpRequest) { xHRObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData() { if ((xHRObject.readyState == 4) && (xHRObject.status == 200)) { var serverResponse = xHRObject.responseXML; var header = serverResponse.getElementsByTagName("book"); var spantag = document.getElementById("cart"); spantag.innerHTML = ""; for (i=0; i
4. Należy uruchomić przykład, zaczynając od strony Catalogue1PHP.htm.
Powinien on działać dokładnie tak samo, jak poprzednio.
Jak to działa W kodzie po stronie klienta nie zmieniono prawie nic — poza zmianą referencji na kod PHP. W czym zatem kod w PHP jest inny? PHP nie ma na przykład wbudowanej obsługi tablic mieszających jako struktur danych. Zamiast tego należy skorzystać z wielowymiarowej tabeli, w której przechowa się zmienną Session. Poza tym jednak kod ten prawie dokładnie odpowiada kodowi w ASP.NET. Ponownie trzeba zająć się czterema scenariuszami:
Użytkownik dodaje przedmiot i przedmiot ten jest już obecny w koszyku z zakupami.
Użytkownik dodaje nowy przedmiot, którego nie ma jeszcze w koszyku z zakupami, natomiast sam koszyk z zakupami już istnieje.
Użytkownik usuwa przedmiot z koszyka z zakupami.
Użytkownik dodaje przedmiot, ale koszyk jeszcze nie istnieje, dlatego trzeba go utworzyć.
Ponieważ w PHP nie jest wymagane silne typowanie zmiennych, kod ten może być nieco krótszy i prostszy od kodu w ASP.NET. Ponieważ nie jest wymagane określone zdarzenie on_load, kod PHP, jaki ma być wykonywany za każdym wywołaniem strony, można umieścić w jej części head.
118
Ajax. Od podstaw Rozpoczyna się od zarejestrowania zmiennej Session o nazwie Cart, która przechowuje koszyk z zakupami. Ustawia się też Content-Type odpowiedzi na text/xml, by można było skorzystać z właściwości responseXML.
Następnie tworzy się dwie zmienne, które będą przechowywały tytuł książki oraz działanie, jakie użytkownik chce wykonać. Są one pobierane ze zbioru $_GET, który został dodany jako łańcuch znaków zapytania do żądania wykonanego przez JavaScript: $newitem = $_GET["book"]; $action = $_GET["action"];
Później sprawdza się zmienną $_Session["Cart"], by przekonać się, czy jest ona pusta. Jeśli nie jest pusta, tworzy się zmienną o nazwie $MDA, w której przechowana zostanie zmienna Session. Ponieważ nie używa się silnego typowania, nie trzeba się martwić o rzutowanie zmiennych PHP z jednego typu na drugi. Zazwyczaj odbywa się to automatycznie. if ($_SESSION["Cart"] != "") { $MDA = $_SESSION["Cart"];
Dalej sprawdza się, czy zmienna $action zawiera słowo Add, które zostało na początku przekazane z JavaScriptu. Jeśli tak jest, mamy do czynienia z jednym z dwóch scenariuszy. Pierwszy z nich to sytuacja, w której ma się już przedmiot w koszyku z zakupami i chce się dodać kolejny, przechować nową wartość w tablicy, przechować tablicę w zmiennej Session, a następnie dokonać serializacji tablicy, jak poniżej: if ($action == "Add") { if ($MDA[$newitem] != "") { $value = $MDA[$newitem] + 1; $MDA[$newitem] = $value; $_SESSION["Cart"] = $MDA; ECHO (toXml($MDA)); }
Ta tablica działa bardzo podobnie do tablicy mieszającej z ASP.NET. Do każdego elementu można się odnieść za pomocą tytułu przechowywanej książki. Wartością indeksu tablicy jest po prostu tytuł książki. Jeśli w koszyku nie ma przedmiotów, wartość ustawia się na pustą, przechowuje tablicę w zmiennej sesyjnej i serializuje ją do postaci XML. else { $MDA[$newitem] = ""; $_SESSION["Cart"] = $MDA; ECHO (toXml($MDA)); } }
W trzecim scenariuszu usuwa się przedmiot poprzez ustawienie tablicy oraz zmiennej Session na puste łańcuchy znaków, a następnie dokonuje się serializacji do postaci XML:
Rozdział 3.
Ajax oraz technologie po stronie serwera
119
else { $MDA= ""; $_SESSION["Cart"] = ""; ECHO (toXml($MDA)); } }
W ostatnim, czwartym scenariuszu (gdy koszyk z zakupami nie istnieje) wykorzystano ten sam kod co w pierwszym: else { $MDA[$newitem] = "1"; $_SESSION["Cart"] = $MDA; ECHO (toXml($MDA)); }
Wartość ustawia się na 1. Tworzy się zmienną Session o nazwie Cart i przypisuje się do niej tablicę. Następnie dokonuje się serializacji tablicy do postaci XML. Choć PHP nie posiada wbudowanego zbioru metod służących specjalnie do tworzenia dokumentów XML, posiada metodę DomDocument. W tym przykładzie można utworzyć dokument XML jako dokument DOM, a następnie utworzyć elementy XML i dodawać je do dokumentu wraz z węzłami tekstowymi tak samo, jak w ASP.NET. Do dyspozycji jest element główny , wewnątrz którego tworzy się element book dla każdego tytułu znajdującego się w koszyku z zakupami. Element book zawiera elementy oraz , do których przypisuje się węzły tekstowe przechowujące dane. function toXml($MDA) { $doc = new DomDocument('1.0'); $cart = $doc->createElement('cart'); $cart = $doc->appendChild($cart); foreach ($MDA as $Item => $ItemName) { $book = $doc->createElement('book'); $book = $cart->appendChild($book); $title $title $value $value
= = = =
$quantity $quantity $value2 = $value2 =
$doc->createElement('title'); $book->appendChild($title); $doc->createTextNode($Item); $title->appendChild($value); = $doc->createElement('quantity'); = $book->appendChild($quantity); $doc->createTextNode($ItemName); $quantity->appendChild($value2);
} $strXml = $doc->saveXML(); return $strXml; }
120
Ajax. Od podstaw Funkcję saveXML wykorzystuje się do skompilowania dokumentu jako jednej całości. Przechowuje się go jako łańcuch znaków i zwraca do funkcji echo. Funkcja ta zapisuje dane do strumienia Response i przekazuje informacje z powrotem z serwera do skryptu po stronie klienta, w którym dokument XML zostaje wykorzystany do złożenia strony HTML.
Serwlety Javy Ostatnia omówiona technologia po stronie serwera wykorzystuje Javę. Choć środowisko uruchomieniowe Javy może być obecne na kliencie, tym razem przedstawione zostanie wykorzystywanie Javy na serwerze z użyciem serwletów. Serwlety (ang. servlet) to aplikacje po stronie serwera napisane w języku programowania Java. Są wykorzystywane do tworzenia interaktywnych stron internetowych i udostępniają te same możliwości, jakich można oczekiwać od PHP czy ASP.NET (na przykład przetwarzanie formularzy, zarządzanie sesją oraz cookies, obsługa logowania). Tak jak w przypadku PHP, choć Java jest technologią własnościową2, jest dystrybuowana za darmo przez firmę Sun i dostępna pod adresem http://java.sun.com. Jak na ironię, Ajax jest obecnie wykorzystywany do wypełniania luki, jaką Java miała wypełnić dekadę temu. Na początku Java wykorzystywała wirtualną maszynę Javy (JVM, Java Virtual Machine), by uruchamiać po stronie klienta aplikacje, które byłyby bardziej interaktywne i miałyby większe możliwości. Akurat to zastosowanie Javy ograniczyło kilka problemów. Pierwszym z nich było to, że znacznik , który był dodatkiem zaakceptowanym przez Netscape (co zostało ustandaryzowane w HTML 3.2), wykorzystywanym do uruchamiania apletów Javy, szybko — w wersji 4.0 HTML — uznany został za przestarzały i odradzany; traktowany był również jako swego rodzaju aberracja. Tak naprawdę cały standard HTML 3.2 był postrzegany jako nieco samowolny. Zaakceptowanym zamiennikiem został znacznik , który od dłuższego czasu obecny był w przeglądarce Internet Explorer, dlatego w efekcie brakowało standardowego sposobu dodawania aplikacji w Javie. Na dodatek wirtualna maszyna Javy, która wymagana była do uruchomienia Javy, była stale uaktualniana, natomiast wersje dołączone do przeglądarek zostawały te same, o ile się ich osobno nie uaktualniło. W rzeczywistości oznaczało to, że, by uruchomić nowsze aplety Javy, często trzeba było najpierw pobrać zupełnie nową wersję wirtualnej maszyny Javy. Ostatnim powodem niepowodzenia było to, że Java przeniosła prawie cały ciężar przetwarzania z powrotem na klienta. Aplety Javy często pobierały się bardzo powoli, a jeszcze wolniej zaczynały działać — w zależności od mocy maszyny użytkownika. Choć Java nadal jest bardzo popularnym językiem oraz środowiskiem programowania, Ajax zdecydowanie przejął jej rolę po stronie klienta. 2
W listopadzie 2006 firma Sun ogłosiła, że kod źródłowy Javy zostanie opublikowany jako wolne oprogramowanie na licencji GNU GPL. Stało się tak w okresie pomiędzy listopadem 2006 a majem 2007; jedynie fragmenty pochodzące od innych podmiotów, które nie zgodziły się na opublikowanie ich na licencji GNU GPL, pozostały kodem własnościowym. Sun planuje je jednak zastąpić implementacjami alternatywnymi — przyp. tłum.
Rozdział 3.
Ajax oraz technologie po stronie serwera
121
To, że Ajax zajął miejsce Javy po stronie klienta, nie oznacza, iż nie można z powodzeniem połączyć Ajaksa z Javą działającą na serwerze.
Przykład wykorzystujący Ajaksa oraz serwlety Javy Wzorzec powinien już być znany. Czas przystosować przykład omawiany w niniejszym rozdziale tak, by w aplikacji opartej na Ajaksie korzystał on z serwletów Javy. By tworzyć i uruchamiać serwlety, potrzebne będą następujące elementy:
J2EE SDK, wersja 2 (http://java.sun.com/products/servlet/download.html) — to aktualna wersja języka programowania Java,
Tomcat@Jakarta (http://tomcat.apache.org/) — serwer, na którym można uruchamiać serwlety.
Serwlety wymagają serwera z obsługą Javy wraz z silnikiem obsługującym serwlety. Należy zainstalować J2EE SDK zgodnie z załączonymi instrukcjami i uruchomić serwer aplikacji Javy. Serwer ten najczęściej działa pod adresami http://localhost:8080, http://localhost:8081 bądź http://localhost:4848. Następnie należy zainstalować serwer Tomcat i uruchomić usługę, na której jest on oparty, zgodnie ze wskazówkami dostarczonymi przy instalacji. Kiedy aplikacja zostanie poprawnie zainstalowana na serwerze WWW, można ją wywołać z JavaScriptu w podobny (choć nieco odmienny) sposób jak poprzednio. Serwlety muszą być skompilowane, zanim będzie się można do nich odnosić, dlatego należy skompilować klasy Javy w pliki .class. Następnie należy się odnieść do pliku .class za pomocą metody open obiektu XMLHttpRequest, jak poniżej: XMLHttpRequestObject.open("POST", "response?value=1", "true");
I znów przykład ten wymaga minimalnej interwencji w przypadku kodu po stronie klienta. Zmieniony zostanie jedynie kod po stronie serwera, a ponieważ w przykładzie tym wykorzystano serwer Tomcat, konieczna będzie również zmiana lokalizacji plików aplikacji. Tomcat wymaga także wykonania kilku czynności konfiguracyjnych, by serwlet działał.
spróbuj sam Przykład koszyka z zakupami w Javie 1.
Należy umieścić wszystkie pliki w folderze C:\Program Files\Apache Software Foundation\Tomcat 5.5\webapps\ROOT (lub w innym folderze, w którym zainstalowano serwer Tomcat). Należy otworzyć plik Catalogue1.htm, zmienić poniższy wiersz i zapisać plik jako Catalogue1Java.htm: ...
...
2. Należy zmienić poniższe podkreślone wiersze w pliku Cart.js w funkcji AddRemoveItem,
by miały one widoczną poniżej formę, a następnie zapisać ten plik jako CartJava.js:
122
Ajax. Od podstaw if(action=="Add") { xHRObject.open("GET", "ManageCartServlet?action=" + action + "&book=" + book + "&value=" + num, true); } else { xHRObject.open("GET", "ManageCartServlet?action=" + action + "&book=" + book + "&value=" + num, true); }
Należy również zmienić poniższe wiersze: if (window.ActiveXObject) { spantag.innerHTML += " " +header[0].firstChild.text; spantag.innerHTML += " " + header[0].lastChild.text + " " + "Usuń przedmiot"; } else { spantag.innerHTML += " " +header[0].childNodes[1].textContent; spantag.innerHTML += " " + header[0].childNodes[3].textContent + " " + "Usuń przedmiot"; }
3. Następnie należy utworzyć plik tekstowy o nazwie ManageCartServlet.java i dodać
do niego następujący kod: import import import import import import import import
javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletResponse; javax.servlet.http.HttpSession; javax.servlet.http.HttpServletRequest; javax.servlet.ServletException; java.io.IOException; java.util.Hashtable; java.util.Iterator;
public class ManageCartServlet extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { String newitem = req.getParameter("book"); String action = req.getParameter("action"); Hashtable ht = new Hashtable(); HttpSession session = req.getSession(true); if (session.getAttribute("cart") != null) { ht = (Hashtable) session.getAttribute("cart"); if ("Add".equals(action)) { if (ht.containsKey(newitem)) { int value = 1; if (ht.containsKey(newitem))
Rozdział 3. {
}
}
Ajax oraz technologie po stronie serwera
Integer currentQuantity = (Integer) ht.get(newitem); value += currentQuantity.intValue();
} ht.put(newitem, new Integer(value)); session.setAttribute("cart", ht); String cartXml = toXml(ht); res.setContentType("text/xml"); res.getWriter().write(cartXml); } else { ht.put(newitem, 1); session.setAttribute("cart", ht); String cartXml = toXml(ht); res.setContentType("text/xml"); res.getWriter().write(cartXml); } } else { ht.remove(newitem); session.setAttribute("cart", null); String cartXml = toXml(ht); res.setContentType("text/xml"); res.getWriter().write(cartXml); ; } } else { ht.put(newitem, 1); session.setAttribute("cart", ht); String cartXml = toXml(ht); res.setContentType("text/xml"); res.getWriter().write(cartXml); }
public String toXml(Hashtable ht) { StringBuffer xmlDoc = new StringBuffer(); xmlDoc.append("\n"); xmlDoc.append("\n"); for (Iterator x = ht.keySet().iterator(); x.hasNext();) { String item = x.next(); int Quantity = ((Integer) ht.get(item)).intValue(); xmlDoc.append("\n"); xmlDoc.append(""); xmlDoc.append(item); xmlDoc.append("\n"); xmlDoc.append(""); xmlDoc.append(Quantity); xmlDoc.append("\n"); xmlDoc.append("\n"); } xmlDoc.append("\n"); return xmlDoc.toString(); }
123
124
Ajax. Od podstaw 4. Należy skompilować aplikację do pliku .class. JDK z firmy Sun zawiera kompilator wiersza poleceń javac. Przy kompilacji niezbędne będzie również
dołączenie API serwletu w następujący sposób (warto zwrócić uwagę na to, że adres URL może się różnić w zależności od instalacji serwera Tomcat). Dla wygody plik ManageCartServlet.java umieszczony został w tym samym folderze co kompilator javac.exe z poniższego polecenia: javac -classpath ".;C:\Program Files\Apache Software Foundation\Tomcat 5.5\ common\lib\servlet-api.jar" ManageCartServlet.java
5. W domyślnej konfiguracja serwera Tomcat skompilowane serwlety umieszczane
są w folderze webapps\ROOT\WEB-INF\classes katalogu instalacyjnego Tomcata. Należy umieścić plik ManageCartServlet.class w tym katalogu. Jeśli uruchamia się serwer po raz pierwszy, należy najpierw utworzyć odpowiedni folder. 6. Należy utworzyć następujący plik web.xml i zapisać go w folderze WEB-INF
znajdującym się w folderze ROOT:
Aplikacja ManageCartServlet Testowanie Ajaksa
ManageCartServlet ManageCartServlet
ManageCartServlet /ManageCartServlet
7. Teraz należy uruchomić przykład raz jeszcze, otwierając stronę
http://localhost:8080/Catalogue1Java.htm, jednak tym razem z użyciem Javy. Przykład będzie działał dokładnie tak samo, jak w przypadku ASP.NET oraz PHP.
Jak to działa Przykład ten w pełni odzwierciedla dwa poprzednie, choć wymaga dodatkowej konfiguracji, by zaczął działać. Ponownie wykorzystuje się dwie metody, które wykonują pożądane zadania. Metoda doGet przypomina metodę OnLoad z ASP.NET, ponieważ jest ona wywoływana za każdym razem, gdy uruchamiana jest strona. Jeśli Czytelnik nie jest zaznajomiony z ASP.NET, wystarczy wiedza, że jest to metoda wywoływana za każdym razem, gdy strona rozpoczyna działanie. Zazwyczaj w pliku PHP jest to kod, który nie został ujęty wewnątrz funkcji. Czas powrócić do czterech scenariuszy. Nie ma sensu ich powtarzać kolejny raz ani też dokładnie analizować podobnego kodu. Zamiast tego warto zwrócić uwagę na najistotniejsze różnice.
Rozdział 3.
Ajax oraz technologie po stronie serwera
125
Ponownie można skorzystać z tablicy mieszającej do przechowania informacji o koszyku z zakupami, a tablica ta mieści się w zmiennej Session. Z punktu widzenia semantyki obsługa sesji w Javie jest nieco bardziej rozwlekła niż w ASP.NET oraz PHP, jednak w dużej mierze działa w ten sam sposób. Ustawia się wartości i przechowuje je w tablicy mieszającej. Wykorzystuje się klucz tablicy mieszającej do przechowania tytułu książki. Ustawia się zawartość zmiennej Session, Content-Type odpowiedzi, a także zapisuje zserializowaną (za pomocą metody toXML) tablicę mieszającą w niemalże identyczny sposób jak w przykładach opartych na ASP.NET oraz PHP. Metoda toXML jest nieco bardziej prymitywna od jej odpowiedników w ASP.NET oraz PHP i by przykład ten pozostał prosty, utworzono obiekt StringBuffer, po czym dynamicznie utworzono łańcuch znaków z dokumentem XML: public String toXml(Hashtable ht) { StringBuffer xmlDoc = new StringBuffer(); xmlDoc.append("\n"); xmlDoc.append("\n");
}
}
for (Iterator x = ht.keySet().iterator(); x.hasNext();) { String item = x.next(); int Quantity = ((Integer) ht.get(item)).intValue(); xmlDoc.append("\n"); xmlDoc.append(""); xmlDoc.append(item); xmlDoc.append("\n"); xmlDoc.append(""); xmlDoc.append(Quantity); xmlDoc.append("\n"); xmlDoc.append("\n"); } xmlDoc.append("\n"); return xmlDoc.toString();
Dane te są zwracane do metody doGet() wraz ze zserializowanym dokumentem XML, a stamtąd z powrotem do klienta. Ponieważ ustawiono Content-Type odpowiedzi na text/xml, dokument XML zostanie poprawnie przetworzony przez obiekt XMLHttpRequest pomimo tego, iż na serwerze został on utworzony jako łańcuch znaków.
Którą technologię powinno się wykorzystywać? Autorzy książki mają nadzieję, że Czytelnik zapoznał się z najpopularniejszymi technologiami po stronie serwera. ASP.NET oraz PHP działają na serwerze IIS. PHP można również uruchomić na serwerze Apache, natomiast serwlety Javy wymagają własnego serwera aplikacji. Żaden z przykładów nie różni się znacząco od pozostałych, a najbardziej skomplikowanymi ich częściami są chyba instalacja technologii po stronie serwera i wykorzystanie jej do osiągnięcia zamierzonego celu.
126
Ajax. Od podstaw Celem niniejszego omówienia nie jest ocena zalet oraz wad wymienionych technologii. Zazwyczaj to konieczność napędza programistów, więc na ogół albo klient nakazuje użycie określonej technologii, albo też autor aplikacji zna jedną z nich na tyle dobrze, że to na niej oprze swoją aplikację. Oczywiście czasami jedna z technologii lepiej od pozostałych nadaje się dla konkretnej implementacji. ASP.NET posiada o wiele bardziej rozbudowaną i skomplikowaną obsługę stanów od PHP, a także zawiera alternatywny sposób zarządzania stanem, który nie wiąże się z wykorzystywaniem cookies. PHP oraz Java działają na większej liczbie platform niż ASP.NET, jednak ASP.NET staje się coraz bardziej wszechobecny. Jeśli chodzi o odpowiedź na pytanie, czy jedna z tych technologii działa lepiej z Ajaksem, czy też lepiej do Ajaksa pasuje, odpowiedź może być tylko jedna — nie. Tak naprawdę lepiej spojrzeć na to z drugiej strony — Ajax wypełnia lukę, którą należało wypełnić w każdej z tych technologii. Wybór należy zatem do programisty i nie powinien on odrzucać Ajaksa tylko dlatego, że jest przywiązany do określonej platformy programistycznej czy technologii. Ajax działa równie dobrze na każdej z nich.
Podsumowanie Niniejszy rozdział był krótkim spojrzeniem na rolę serwera w aplikacjach opartych na Ajaksie. Jeśli Czytelnik zainteresował się Ajaksem i oczekiwał, że w technologii tej nie ma się do czynienia z serwerem, może się czuć nieco zawiedziony. W przypadku większości aplikacji nie da się tego prawdopodobnie obejść. Rozpoczęto od zbadania roli serwera w tradycyjnym cyklu żądanie-odpowiedź w programowaniu webowym, a następnie porównano ją z wykonywaniem zapytań do serwera w Ajaksie oraz JavaScripcie. Następnie rozszerzono omówienie każdego z kroków tego cyklu. Później krótko omówiono każdą z trzech wybranych technologii po stronie serwera. Utworzono przykład z koszykiem z zakupami oraz dopasowano do niego stronę po stronie serwera napisaną w ASP.NET, PHP oraz Javie, by zobaczyć, jak niewiele różnic występuje pomiędzy tymi technologiami. Niewiele miejsca poświęcono operacjom po stronie klienta, jednak wspomniano nieco o tym, w jaki sposób obiekt XMLHttpRequest wykorzystywany jest do inicjowania żądań i otrzymywania danych. W rozdziale 4. kwestie te omówione zostaną o wiele bardziej szczegółowo wraz z metodami wykorzystywanymi w Ajaksie do tworzenia żądania oraz obsługiwania jego wyników.
Ćwiczenia Sugerowane rozwiązania poniższych zadań znajdują się w dodatku A. 1.
Należy dodać numer ISBN do dokumentu XML. Dlaczego może to być użyteczne?
2. Należy ulepszyć koszyk z zakupami, tak by numer ISBN był teraz w nim widoczny.
4
Techniki Ajaksa W rozdziale 1. wspomniano, że kiedy ludzie mówią o Ajaksie, mają na myśli zazwyczaj wykorzystywanie obiektu XMLHttpRequest oraz skryptu po stronie serwera do interakcji ze stroną internetową w tle. Wspomniano również, że obiekt XMLHttpRequest nie musi być jedynym sposobem, za pomocą którego organizuje się komunikację pomiędzy klientem a serwerem. Niektóre techniki poprzedzające obiekt XMLHttpRequest obejmowały użycie ukrytych ramek, natomiast inne techniki — alternatywne dla XMLHttpRequest — wykorzystują dynamiczne ładowanie skryptu bądź uprzednie ładowanie obrazków czy używanie cookies. W niniejszym rozdziale krótko przedstawione zostaną wszystkie te metody — mieszczące się w obrębie Ajaksa. Choć brzmi to tak, jakby do opisania pozostawało wiele różnych kwestii, większość tych technik jest stosunkowo prosta, a każda z nich zasługuje na krótkie omówienie. Na początek przedstawiony zostanie obiekt XMLHttpRequest i to jemu poświęcone zostanie najwięcej miejsca, gdyż jest on centralną częścią wielu aplikacji opartych na Ajaksie. Jest to również rozwiązanie, które dla większości programistów ma najszersze zastosowanie. Omówione zostanie, w jaki sposób wykorzystuje się ten obiekt wraz z metodami POST oraz GET, gdyż w przeciwieństwie do stron ASPX czy PHP sposób użycia XMLHttpRequest z tymi dwoma metodami znacznie się różni. Przedstawione zostaną również najczęściej popełniane błędy oraz problemy, z jakimi można się spotkać przy wykorzystywaniu tego obiektu. Niektóre z tych problemów można napotkać, kiedy próbuje się sprawić, by strona działa we wszystkich przeglądarkach; temat ten będzie powracał również w kolejnych rozdziałach. Następnie omówiona zostanie każda z alternatywnych dla Ajaksa technik wraz z krótkim przykładem jej wykorzystania. W niniejszym rozdziale omówione zostaną zatem następujące kwestie:
obiekt XMLHttpRequest,
ukryte ramki,
ukryte ramki typu iframe,
dynamiczne ładowanie skryptu,
uprzednie ładowanie obrazków oraz wykorzystywanie cookies.
128
Ajax. Od podstaw
Obiekt XMLHttpRequest Obiekt XMLHttpRequest został powołany do życia jako kontrolka ActiveX w przeglądarce Internet Explorer 5.0, choć sam pomysł tego obiektu pochodzi z Outlook Web Access 2000. Outlook Web Access 2000 był usługą pocztową programu Outlook, która wykorzystywana była do umożliwienia dostępu do poczty elektronicznej (pobierania e-maili, sprawdzania kalendarza, uaktualniania kontaktów) w czasie, gdy jest się w ruchu. Usługa ta pozwalała aplikacji na wykonywanie własnych żądań HTTP po stronie klienta. Szybko w tym samym celu obiekt ten pojawił się w przeglądarce Internet Explorer 5. Kontrolki ActiveX mają niewygodną właściwość polegającą na tym, że działają tylko w przeglądarce Internet Explorer. Obiekt ten jednak szybko zyskał popularność i został później wprowadzony do przeglądarek Mozilla 1.0, Netscape 7, Safari 1.2 oraz Opera 7.60. Choć Opera zaimplementowała obiekt XMLHttpRequest w wersji 7.60, niektóre błędy związane z jego użyciem usunięte zostały dopiero w wersji 8.0. Jeśli zatem Czytelnik ma wersję 7.60, powinien pobrać bardziej aktualne wydanie ze strony www.opera.com, na której można obecnie znaleźć wersję 9.21.
Oznaczało to, że implementacja tego obiektu była różna w wersji używanej w Internet Explorerze oraz w wersji wykorzystywanej we wszystkich innych przeglądarkach (która była częścią obiektu window). W praktyce oznacza to, że trzeba używać skryptu wykrywającego przeglądarkę, by sprawdzić, jaką przeglądarkę posiada użytkownik, zanim będzie można utworzyć instancję tego obiektu. Konsorcjum W3C wzięło na siebie opracowanie implementacji tego obiektu z zamiarem utworzenia wspólnego podzbioru właściwości oraz metod, które mogą być wykorzystywane we wszystkich przeglądarkach. Kolejną wersję roboczą efektów pracy tego organu standaryzacyjnego można znaleźć pod adresem www.w3.org/ TR/XMLHttpRequest. W rezultacie XMLHttpRequest jest teraz dołączony do przeglądarki Internet Explorer 7 jako obiekt wbudowany (co oznacza, że działa on tak samo, jak w przeglądarkach takich jak Firefox), natomiast obiekt XMLHTTP jest nadal obecny jako kontrolka ActiveX. Ponieważ jednak przeglądarka Internet Explorer 6 stała się integralną częścią systemu operacyjnego Windows XP, przez długi czas będzie trzeba jeszcze uwzględnić to w swoich aplikacjach. Powyższe informacje wyjaśniają nieco historię obiektu, jednak nie mówią nic o jego działaniu. Zgodnie z drugą wersją roboczą standardu obiektu XMLHttpRequest obiekt ten może być wykorzystywany do „pozwalania skryptom na łączenie się z ich serwerem za pomocą HTTP”. Innymi słowy, obiekt ten pozwala skryptom na komunikację z serwerem poza normalnym scenariuszem żądań i odpowiedzi HTTP. Podstawowym celem obiektu XMLHttpRequest jest możliwość wykorzystywania samego HTML oraz skryptu do bezpośredniego połączenia się z warstwą danych przechowywaną na serwerze. W wielu przypadkach pozwala on obejść konieczność wykonywania skryptów po stronie serwera. W rozdziale 1. omówiono, w jaki sposób można wykorzystać DOM do utworzenia dynamicznego systemu menu, w którym opcje menu są w całości wypełniane danymi pobranymi z pliku XML. Zaletą używania obiektu XMLHttpRequest jest to, że nie
Rozdział 4.
Techniki Ajaksa
129
trzeba przesyłać strony bądź odświeżać jej, ponieważ zmiany w danych (takie jak tekst menu) są natychmiast odzwierciedlane na stronie wyświetlanej w przeglądarce. Jest to integralną częścią tworzenia spójnych i bogatych interfejsów użytkownika, co jest celem aplikacji opartych na Ajaksie. Czas zatem przyjrzeć się wykorzystaniu tego obiektu w praktyce.
Tworzenie obiektu XMLHttpRequest W rozdziale 1. przedstawiono, w jaki sposób można utworzyć obiekt XMLHttpRequest zarówno w przeglądarce Firefox, jak i Internet Explorer. Na wypadek gdyby Czytelnik już o tym zapomniał (albo był typem osoby, która zawsze pomija pierwszy rozdział każdej książki), poniżej znajduje się kod w JavaScripcie, który jest do tego niezbędny. W przeglądarkach Internet Explorer 7, Firefox, Safari oraz Opera składnia potrzebna do utworzenia obiektu XMLHttpRequest jest następująca: var xmlRequest = new XMLHttpRequest();
W przeglądarkach Internet Explorer 5 oraz 6 kod ten będzie wyglądał jak poniżej: var xmlRequest = new ActiveXObject("Microsoft.XMLHTTP");
Ponieważ w JavaScripcie wielkość liter ma znaczenie, należy pamiętać, by poprawnie zapisać powyższy — nieco nietypowy — kod. W przeciwnym razie nie uda się utworzyć niczego. Oczywiście samo utworzenie tego obiektu na stronie nie przyniesie żadnych widocznych efektów ani też nie sprawi, że obiekt ten zacznie od razu działać. Obiektu XMLHttpRequest można używać na dwa sposoby — synchronicznie lub asynchronicznie.
Użycie synchroniczne Obiektu XMLHttpRequest można użyć synchronicznie zgodnie z poniższym wzorcem: 1.
Utworzenie obiektu.
2. Utworzenie żądania. 3. Przesłanie żądania. 4. Czekanie z przetwarzaniem do momentu otrzymania odpowiedzi.
Odpowiada to temu, co wykonuje się normalnie, gdy przesyła się żądanie do serwera i czeka na odpowiedź. Prawdziwa moc tkwi jednak w asynchronicznym wykorzystaniu obiektu XMLHttpRequest.
130
Ajax. Od podstaw
Użycie asynchroniczne Kiedy używa się obiektu XMLHttpRequest asynchronicznie, należy wywołać go za pomocą zdarzenia onreadystatechange. Gdy zdarzenie to zostanie wywołane, należy sprawdzić zawartość właściwości readystate, zanim aplikacja wykona jakieś działanie. Oznacza to, że należy zastosować się do poniższego wzorca: 1.
Utworzenie obiektu.
2. Skonfigurowanie zdarzenia readystatechange, tak by wywoływało ono określoną
funkcję. 3. Ustawienie właściwości readyState w celu sprawdzenia, czy dane są gotowe.
Jeśli tak nie jest, ponowne sprawdzenie za jakiś czas. Jeśli dane są gotowe, przejście do kolejnego kroku. 4. Otwarcie żądania Request. 5. Przesłanie żądania Request. 6. Kontynuowanie przetwarzania i przerwanie go wtedy, gdy otrzyma się
odpowiedź. Cała operacja ze zdarzeniem onreadystatechange wykonywana jest w tle i pozwala na wykorzystywanie obiektu XMLHttpRequest w sposób asynchroniczny. Może to zabrzmieć nieco dziwnie, ale sposób działania tego obiektu przypomina sytuację, gdy wybieramy się na przejażdżkę z dziećmi. Kiedy dzieci osiągają wiek pięciu lat, co pięć minut zadają klasyczne pytanie: „Czy jesteśmy już na miejscu?”. Nie ma znaczenia, jak blisko bądź daleko jest się od celu; jedyne, co się zmienia, to odpowiedź na pytanie dzieci. Na początku mówi się coś w stylu: „Jeszcze sporo drogi przed nami”, w połowie podróży: „Połowa drogi za nami”. Pod koniec zapewne odpowiedź będzie brzmiała: „Już niedaleko”. Na końcu zaś mówi się: „Uf, wreszcie jesteśmy na miejscu”. Oczywiście tylko ta ostatnia odpowiedź ma szansę zapobiec wybuchowi złości ze strony małych pasażerów. Obiekt XMLHttpRequest jest podobny, to znaczy ciągle informuje o swoim stanie za pomocą właściwości readyState, jednak tak naprawdę interesująca jest jedynie informacja o tym, że ładowanie danych zostało zakończone — bo dopóki tak się nie stanie, nie można wykorzystywać odpowiednich właściwości oraz metod.
Właściwość readyState Właściwość readyState wskazuje, na jakim etapie przesyłania bądź otrzymywania danych jest obiekt XMLHttpRequest. Obiekt ten przechodzi przez pięć możliwych zmian stanu. Ich kody są następujące — wskazują one na etap cyklu ładowania danych:
0 — Uninitialized (niezainicjalizowany) — oznacza to, że obiekt został utworzony, ale nie zainicjalizowany. Innymi słowy, metoda open nie została jeszcze wywołana.
Rozdział 4.
Techniki Ajaksa
1 — Open (otwarty) — ma miejsce, kiedy obiekt został utworzony i zainicjalizowany, jednak nie wywołano jeszcze metody send.
2 — Sent (wysłany) — oznacza, że wywołana została metoda send, jednak obiekt oczekuje na zwrócenie kodu statusu oraz nagłówków.
3 — Receiving (otrzymuje) — oznacza, że pewne dane zostały otrzymane, ale nie wszystkie. Nie będzie się w stanie wykorzystać właściwości obiektu, aby zobaczyć częściowe wyniki, ponieważ status oraz nagłówki odpowiedzi nie są w pełni dostępne.
4 — Loaded (załadowany) — jest to ostatni etap, w którym wszystkie dane zostały odebrane i są dostępne. Zazwyczaj jest to wartość kodu readyState, której istnienie się sprawdza.
131
Po załadowaniu danych można wykorzystać inne właściwości oraz metody do pobrania danych z odpowiedzi na wysłane żądanie.
Właściwości oraz metody obiektu XMLHttpRequest Jak widać w tabelach 4.1 oraz 4.2, obiekt XMLHttpRequest ma dość niewielką liczbę metod oraz właściwości wykorzystywanych w jego działaniu. Tabela 4.1. Właściwości obiektu XMLHttpRequest Właściwość
Opis
onreadystatechange
Zwraca bądź ustawia program obsługi zdarzeń dla żądań asynchronicznych.
readyState
Zwraca kod reprezentujący stan żądania. Może to być jeden z poniższych: 0 — Uninitialized (niezainicjalizowany) 1 — Open (otwarty) 2 — Sent (wysłany) 3 — Receiving (otrzymuje) 4 — Loaded (załadowany)
responseBody (tylko w IE7)
Zwraca odpowiedź HTTP w formie tablicy bajtów bez znaku.
responseText
Zwraca odpowiedź HTTP w formie łańcucha znaków.
responseXML
Zwraca odpowiedź HTTP w formie obiektu XML z DOM.
status
Zwraca kod statusu HTTP.
statusText
Zwraca tekst opisujący, co oznacza określony kod statusu HTTP.
W tabeli 4.2 zaprezentowano metody wykorzystywane przy wykonywaniu różnych funkcji.
132
Ajax. Od podstaw
Tabela 4.2. Metody obiektu XMLHttpRequest Metoda
Opis
abort
Anuluje wykonywane żądanie.
getAllResponseHeaders
Pobiera całą listę nagłówków odpowiedzi HTTP.
getResponseHeader
Pobiera jedynie określony nagłówek odpowiedzi HTTP.
open
Przyjmuje kilka argumentów. Pierwszy przypisuje atrybut metody, drugi docelowy adres URL, natomiast trzeci określa, czy żądanie przesyłane jest synchronicznie (false), czy też asynchronicznie (true).
send
Przesyła żądanie do serwera.
setRequestHeader
Dodaje własny nagłówek HTTP do żądania.
Jak widać, można wykorzystać program obsługi zdarzeń onreadystatechange do wskazania, jaki kod powinien zostać wykonany, metodę open do utworzenia żądania, natomiast metodę send — do przesłania go. Dzięki właściwości readyState wiadomo dokładnie, kiedy wykonać kod, który będzie działał po otrzymaniu odpowiedzi, natomiast właściwości responseText oraz responseXML można wykorzystać do pobrania odpowiedzi. Na koniec metoda abort służy do anulowania wykonywanego żądania. Choć, jak widać w tabelach, istnieje kilka innych metod oraz właściwości, to jednak większość aplikacji opiera się na tych siedmiu wymienionych. Czas zatem przyjrzeć się bardzo prostemu przykładowi obiektu, który będzie działał we wszystkich przeglądarkach.
spróbuj sam Dynamiczne wyświetlanie wykorzystujące obiekt XMLHttpRequest Jedną ze wspomnianych w rozdziale 1. stron była Basecamp, która wykorzystywała Ajaksa w sposób nierzucający się w oczy do dynamicznego wyświetlania części strony na żądanie. Warto zatem przyjrzeć się przykładowi wykorzystującemu obiekt XMLHttpRequest do naśladowania tej techniki i wyświetlenia części strony na żądanie, po kliknięciu odnośnika. Do strony dodany zostanie niewielki skrypt po stronie serwera. Można będzie również wykorzystać ASP.NET bądź PHP — w zależności od preferencji. 1.
Należy zlokalizować folder o nazwie BegAjax w katalogu głównym serwera WWW. Wewnątrz niego należy utworzyć folder o nazwie r04.
2. Należy utworzyć następujący skrypt po stronie serwera i zapisać go jako
XmlHttpRequest.js: var xHRObject = false; if (window.XMLHttpRequest) { xHRObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); } function sendRequest(data) {
Rozdział 4.
Techniki Ajaksa
xHRObject.open("GET", "display.php?value=" + data, true); xHRObject.onreadystatechange = getData; xHRObject.send(null); } function getData() { if (xHRObject.readyState == 4 && xHRObject.status == 200) { var serverText = xHRObject.responseText; if(serverText.indexOf('|' != -1)) { element = serverText.split('|'); document.getElementById(element[0]).innerHTML = element[1]; } } }
Jeśli Czytelnik chce w tym przykładzie wykorzystać ASP bądź ASP.NET, powinien zmienić pogrubiony wiersz na następujący: xHRObject.open("GET", "display.aspx?value=" + data, true);
3. Należy utworzyć następującą stronę HTML i zapisać ją jako display.htm:
Kontakty Kalendarz Reklamy
4. Na koniec, jeśli chce się wykorzystywać PHP, należy dodać następujący kod
i zapisać go jako display.php:
Paryż La Splendide Turystyczny 100
Londyn The Rilton Luksusowy 300
6. Należy otworzyć stronę frameset.htm w przeglądarce i wybrać opcję Londyn
z listy rozwijanej, a także opcję Luksusowy z przycisków opcji, jak na rysunku 4.6. 7. Teraz należy wybrać przycisk opcji Turystyczny. Tekst poniżej zmienia się,
odzwierciedlając niedostępność danych, co jest widoczne na rysunku 4.7.
151
152
Ajax. Od podstaw
Rysunek 4.6. Wybranie opcji Londyn oraz Luksusowy
Rysunek 4.7. Tekst zmienia się po wybraniu przycisku opcji Turystyczny
Jak to działa Powyższy przykład wykorzystuje ukryte ramki. Na stronie frameset.htm utworzono dwie ramki:
Rozdział 4.
Techniki Ajaksa
153
Pierwsza odnosi się do widocznej strony current.htm. Druga ramka pozostała pusta. Pierwsza strona zawiera tylko listę rozwijaną, przyciski opcji oraz element div, w którym wyświetlane są informacje o hotelach.
Londyn Paryż Nowy Jork Chicago Seattle
Przedział cenowy:
Turystyczny Standardowy Luksusowy
Lista rozwijana o identyfikatorze selectCity wywołuje funkcję retrieveInformation() ze skryptu HiddenFrame.js za pomocą metody onchange, natomiast przyciski opcji wywołują tę samą funkcję za pomocą zdarzenia onclick. Funkcja retrieveInformation() ustawia dwie zmienne, city oraz type, które zanotowały wartości elementów wybranych przez użytkownika w widocznej ramce. Wszystkie przyciski opcji noszą tę samą nazwę, natomiast do pobrania ich wykorzystano metodę document.getElementsByTagName. Następnie sprawdza się wartość każdego z nich za pomocą iteracji, dopóki nie znajdzie się przycisku ustawionego na true. Wartość przypisywana jest do zmiennej type. var var var for {
}
city = document.getElementById("selectCity").value; type = ""; input = document.getElementsByTagName("input"); (var i=0; i < input.length; i++) if (input.item(i).checked == true) { type = input.item(i).value; }
Następnie przypisuje się lokalizację do pustej ukrytej ramki, dodając zmienne type oraz city do łańcucha znaków zapytania. top.frames["hiddenframe"].location = "retrieveHotelInformation.php?city=" + city + "&type=" + type;
Ponieważ kod po stronie serwera nie jest istotny dla techniki z ukrytymi ramkami, nie zostanie omówiony szczegółowo. Kod po stronie serwera ładuje plik XML, pobiera wartości łańcucha znaków zapytania, a następnie decyduje, jakie elementy należy wyświetlić — w zależności od tego, czy wartości elementów city oraz type pasują do wartości wybranych przez użytkownika. Później kod dynamicznie zapisuje je do znacznika div w ukrytej ramce o nazwie displayinfo.
154
Ajax. Od podstaw Na końcu kodu po stronie serwera znajduje się znacznik body ze zdarzeniem onload, które wywołuje funkcję initialize() z kodu w JavaScripcie. Funkcja ta szuka utworzonego dynamicznie elementu w ukrytej ramce: function initialize() { var hiddenForm = document.getElementById('displayinfo'); if(hiddenForm != null) { parent.frames[0].document.getElementById('information').innerHTML = hiddenForm.innerHTML; } }
Jeśli element ten istnieje na stronie, można uzyskać dostęp do odpowiadającego mu znacznika o nazwie information w widocznej stronie current.htm i przenieść informacje za pomocą właściwości innerHTML. Jak widać, technika ta jest stosunkowo prosta, jednak potencjalnie pozwala na przechowywanie informacji w ukrytej ramce i wywoływanie ich tylko wtedy, gdy są one niezbędne.
Zalety oraz wady Jedną oczywistą zaletą tej techniki jest to, że nie jest potrzebne stosowanie kodu dla określonych przeglądarek, ponieważ wszystkie nowoczesne przeglądarki obsługują ramki. Jeśli chodzi o przesyłanie plików na serwer, nie da się tego tak naprawdę osiągnąć za pomocą obiektu XMLHttpRequest, jednak jest to możliwe dzięki ukrytym ramkom. Główną wadą tej techniki jest to, że nie wszystkie starsze przeglądarki potrafią poprawnie ukrywać ramki. Pomimo ustalenia szerokości oraz wysokości ramki na zero nadal pozostałoby w nich szpetne obramowanie. Rozwiązanie to wprowadza także dodatkowy poziom skomplikowania do interakcji pomiędzy klientem a serwerem, co może nie być pożądane.
Ukryte ramki typu iframe W standardzie HTML 4.0 wprowadzono nowy element — , od angielskiego inline frame, co po polsku tłumaczone jest najczęściej jako ramka pływająca1. Ramki pływające działają tak samo jak obrazki, to znaczy tekst będzie zawijany wokół nich, jednak nie mogą one zawierać osobnych stron internetowych tak jak normalne ramki. W przeciwieństwie do klasycznych ramek nie muszą one być również umieszczane w osobnym zestawie ramek. Zostały one wprowadzone w przeglądarce Internet Explorer 3, jednak w przeglądarce Netscape Navigator nie były obsługiwane aż do wersji 6. Mogą one być tworzone dynamicznie za pomocą skryptów, a dostęp do nich odbywa się w ten sam sposób, jak do zwykłych ramek.
1
Ramki typu iframe nie pojawiają się już jednak w specyfikacji XHTML 1.1, są obecne jedynie w HTML 4 oraz XHTML 1.0 Transitional oraz Frameset; zamiast nich należy używać elementów object — przyp. tłum.
Rozdział 4.
Techniki Ajaksa
155
Pomysł Sposób wykorzystania ramek typu iframe jest taki sam, jak w przypadku ramek ukrytych: 1.
Skrypt wykonuje wywołanie ukrytej ramki.
2. Za pośrednictwem ukrytej ramki wykonywane jest żądanie do serwera. 3. Odpowiedź otrzymana z serwera trafia do ukrytej ramki. 4. Przy wywołaniu zdarzenia (zazwyczaj onload) dane transferowane są z ukrytej
ramki do ramki widocznej. Ramki pływające mogą być wykorzystywane jako bezpośredni zastępnik ramek ukrytych. Ponieważ ich zaletą jest to, że nie trzeba ich umieszczać w zestawie ramek, można wykorzystać JavaScript do dynamicznego dodania ich do strony w dowolnym momencie. Ramki typu iframe są lepszą alternatywą od ramek ukrytych i zapewne ze względu na większą elastyczność zawsze stanowiłyby lepszy wybór, jednak, niestety, nie są tak dobrze obsługiwane przez wszystkie przeglądarki i istnieją pewne różnice w ich implementacji pomiędzy przeglądarkami Firefox a Internet Explorer.
spróbuj sam Wykorzystywanie ukrytych ramek pływających do przekazywania informacji Czas wrócić do poprzedniego przykładu i usunąć z niego zestaw ramek, a zamiast tego dynamicznie utworzyć ramkę typu iframe, która wykona to samo zadanie. Jest to stosunkowo proste do zrobienia, jednak rozwiązanie to nie jest wolne od wad, jak można by sobie tego życzyć. 1.
Należy otworzyć plik current.htm i skopiować go do dokumentu o nazwie currentiframe.htm, dodając poniższe wyróżnione wiersze:
Cel podróży:
...
2. Następnie należy skopiować plik HiddenFrame.js i nazwać go HiddenIframe.js.
Teraz należy dodać do niego następującą funkcję: function createiframe() { var iframe = document.createElement("iframe"); iframe.style.border = "0px"; iframe.style.width = "0px"; iframe.style.height = "0px"; document.body.appendChild(iframe); }
156
Ajax. Od podstaw 3. W tym samym pliku należy odnaleźć funkcję initialize i zmienić w niej
poniższy wiersz: function initialize() { var hiddenForm = document.getElementById('displayinfo'); if(hiddenForm != null) { parent. document.getElementById('information').innerHTML = hiddenForm.innerHTML; } }
4. W funkcji retrieveInformation trzeba zmienić następujący wiersz: function retrieveInformation() { var city = document.getElementById("selectCity").value; var type = ""; var input = document.getElementsByTagName("input"); for (var i=0; i < input.length; i++) { if (input.item(i).checked == true) { type = input.item(i).value; } } top.frames[0].location = "retrieveHotelInformation2.php?city=" + city + "&type=" + type; }
5. Należy przejść do kodu po stronie serwera (w PHP bądź ASP.NET) i poprawić
wiersz odwołujący się do skryptu w następujący sposób, po czym zapisać stronę jako retrieveHotelInformation2(.aspx bądź .php).
6. Należy uruchomić stronę currentiframe.htm w przeglądarce. Działa ona dokładnie
tak samo, jak poprzedni przykład z ukrytymi ramkami, co widać na rysunku 4.8.
Rysunek 4.8. Uruchomienie strony currentiframe.htm w przeglądarce
Rozdział 4.
Techniki Ajaksa
157
Jak to działa Oryginalny przykład z ukrytą ramką działał w następujący sposób:
Ramka widoczna przekazywała informacje do ramki ukrytej, co było de facto odwołaniem się do serwera.
Serwer zwracał informacje do znacznika w ukrytej ramce.
Zawartość była przenoszona ze znacznika w ramce ukrytej do znacznika w ramce widocznej.
To, co dzieje się w zmodyfikowanym przykładzie, jest nieco bardziej skomplikowane. Trzeba utworzyć ramkę iframe dynamicznie, a następnie ustawić jej właściwości wysokości, szerokości oraz obramowania na zero, by w praktyce była ona niewidoczna na stronie. Następnie do strony HTML dodaje się element w poniższy sposób: function createiframe() { var iframe = document.createElement("iframe"); iframe.style.border = "0px"; iframe.style.width = "0px"; iframe.style.height = "0px"; document.body.appendChild(iframe); }
Zmieniono również stronę HTML, tak by wywoływała ona funkcję currentiframe(), kiedy się ją załaduje. Poprawiono także funkcję initialize(), by zapisywała informacje z powrotem do elementu na stronie; nie muszą one już przechodzić przez zestaw ramek, by można było uzyskać do nich dostęp. parent.currentframe.document.getElementById('information').innerHTML = hiddenForm.innerHTML;
Zmieniono także odniesienie do ramki w funkcji retrieveInformation. Następnie przypisano rezultaty ze strony na serwerze do ukrytej ramki iframe, jak poniżej: top.frames[1].location = "retrieveHotelInformation2.php?city=" + city + "&type=" + type;
W przykładzie tym usunięto stronę z zestawem ramek, dynamicznie utworzono ramkę iframe, która ją zastępuje, i wykorzystano tę ramkę do przekazania informacji do serwera oraz z niego. Nic więcej nie trzeba było zmieniać. Jeśli chce się dynamicznie pobrać zawartość formularza, w Internet Explorerze należy skorzystać z właściwości contentWindow.document, by móc pobrać element document ramki iframe. W przeglądarce Firefox należy natomiast użyć właściwości contentDocument: doc = iframe.contentDocument || iframe.contentWindow.document;
Kiedy wykorzystuje się bardziej skomplikowane przykłady od tego, może się zdarzyć, że przeglądarka będzie potrzebowała więcej czasu na załadowanie dokumentu. Można zatem sprawdzić wartość właściwości readyState przez uzyskaniem dostępu do dokumentu, jak poniżej:
158
Ajax. Od podstaw doc = iframe.contentDocument || iframe.contentWindow.document; if (typeof doc.readyState != "undefined" && doc.readyState != "complete") { doc.onreadystatechange = function() { if (doc.readyState == "complete") { ... } } } else { ... }
W takiej sytuacji będzie się miało gwarancję, że ramka iframe została w pełni załadowana.
Zalety oraz wady Przykład ten jest dość prosty, choć w bardziej skomplikowanych przypadkach trzeba zdawać sobie sprawę z problemów z działaniem w różnych przeglądarkach. Tak naprawdę może się skończyć tak, że będzie się miało osobne metody dla przeglądarek Internet Explorer 5, 5.5, 6 oraz 7, a także Firefox, jeśli nie będzie się wystarczająco ostrożnym. W przeglądarce Internet Explorer 5 dynamiczne tworzenie ramek typu iframe nie jest możliwe. Pomimo tych niewielkich przeszkód ramki pływające stanowią zdecydowane ulepszenie względem zwykłych ukrytych ramek. Czas jednak rozważyć inną technikę.
Dynamiczne ładowanie skryptu Autor książki Ajax. Zaawansowane programowanie (Helion, 2006) Nicholas Zakas omawia kolejną zaprezentowaną sztuczkę w artykule dostępnym pod adresem www.webreference.com/ programming/ajax_tech/. Sztuczka ta jest już w użyciu od pewnego czasu jako alternatywa dla obiektu XMLHttpRequest. Określana jest mianem dynamicznego ładowania skryptu. Ma ono miejsce wtedy, gdy JavaScript tworzony jest dynamicznie za pomocą DOM, natomiast atrybut src jest również przypisywany dynamicznie. Plik źródłowy JavaScriptu jest pobierany i wykonywany dopiero po dodaniu go do strony.
Pomysł Pomysł jest w istocie bardzo prosty: 1.
Dodaje się skrypt do strony.
2. Skrypt dynamicznie dodaje do strony inny skrypt, dodając atrybut src
w późniejszym czasie. 3. Skrypt inicjuje dialog z serwerem.
Rozdział 4.
Techniki Ajaksa
159
spróbuj sam Dynamiczne ładowanie skryptu Czas spojrzeć na przykład. Utworzony zostanie bardzo prosty i podstawowy przykład, w którym pobiera się pojedynczy skrypt i dynamicznie tworzy jeden z trzech innych skryptów — w zależności od tego, który przycisk opcji na stronie internetowej zostanie wybrany przez użytkownika. By uprościć przykład, dialog z serwerem nie zostanie zainicjowany, ponieważ metoda ta ma pewne pułapki omówione w dalszej części podrozdziału. 1.
Należy utworzyć stronę HTML zatytułowaną ScriptLoader.htm.
Który skrypt chcesz załadować?
Skrypt 1
Skrypt 2
Skrypt 3
2. Następnie należy utworzyć skrypt o nazwie ScriptLoader.js. function retrieveInformation(data) { var newScript = document.createElement("script"); newScript.src = "script" + data + ".js"; document.body.appendChild(newScript); }
3. Teraz tworzy się kolejny skrypt — script1.js. alert ("Czy jesteś pewien, że chcesz załadować pierwszy skrypt?");
4. Następny utworzony skrypt to script2.js. alert ("Drugi skrypt to też nie przelewki!");
5. Ostatnim skryptem, jaki należy utworzyć, jest script3.js, zawierający
poniższy kod. alert ("To najwyższy stopień wtajemniczenia, skrypt numer trzy!");
6. Teraz należy otworzyć stronę ScriptLoader.htm w przeglądarce i kliknąć pierwszy
przycisk opcji, jak pokazano na rysunku 4.9.
160
Ajax. Od podstaw
Rysunek 4.9. Kliknięcie pierwszego przycisku opcji na stronie ScriptLoader.htm 7. Kliknięcie pozostałych przycisków opcji spowoduje wykonanie pozostałych
skryptów.
Jak to działa Przykład ten jest dość kapryśny, jednak ma na celu pokazanie, że bardzo łatwo jest załadować drugi skrypt w programie i w dynamiczny sposób ustalić jego atrybuty. W kodzie w JavaScripcie znajdowały się tylko trzy wiersze, które były za to odpowiedzialne: var newScript = document.createElement("script"); newScript.src = "script" + data + ".js"; document.body.appendChild(newScript);
Pierwszy wiersz tworzy element script. Drugi ustawia atrybut src. Ładuje się różny skrypt w zależności od tego, który przycisk opcji został wybrany przez użytkownika. Ostatni wiersz dodaje nowy element do elementu body. W tym momencie skrypt zostaje wykonany. Choć drugi skrypt nie został użyty do komunikacji z serwerem, nie byłoby trudne dodanie w każdym ze skryptów osobnego odwołania do serwera, które albo wywołuje różne strony znajdujące się na serwerze, albo przekazuje do niego jakieś informacje.
Rozdział 4.
Techniki Ajaksa
161
Zalety oraz wady Zaletą tej techniki jest to, że można mieć kilka różnych skryptów i dynamicznie ładować odpowiedni w zależności od okoliczności. Jest to też jeszcze jedna możliwość inicjowania odwołania do serwera. Istnieją jednak również liczne wady tego rozwiązania. Pierwsza z nich jest taka, że nie można ustalić, czy skrypt został poprawnie załadowany, ponieważ nic nie jest zwracane z drugiego skryptu. Drugi problem związany jest z tym, że w przeglądarce Internet Explorer dynamiczne ładowanie skryptu zatrzymuje wszelkie inne przetwarzanie. Jednym z możliwych zastosowań tej metody mogłoby być dynamiczne ładowanie animowanego obrazka .gif w czasie przesyłania pliku na serwer. Niestety, w przeglądarce Internet Explorer nawet animowanie obrazka zostaje zatrzymane Rozwiązanie to jest także ograniczone do metody GET i nie można stosować go w połączeniu z metodą POST. Ponieważ korzysta ono z DOM, jest się ograniczonym do nowocześniejszych przeglądarek, od wersji 4 w górę. Najważniejszą jednak wadą tego rozwiązania jest to, że w przeglądarkach Internet Explorer 5 oraz 6 powoduje ono potencjalny wyciek pamięci (ang. memory leak). Choć pozornie wygląda ono na dość interesującą metodę, z pewnością jest rzadziej stosowane ze względu na nieprzewidywalny wynik w różnych przeglądarkach. Taki problem nie występuje jednak w przypadku ostatniej omówionej w tym rozdziale techniki.
Obrazki oraz cookies Używanie (czy też nadużywanie) obrazków na stronach internetowych oraz w poczcie elektronicznej spowodowało, że nawet najważniejsze aplikacje, takie jak Outlook firmy Microsoft, zmieniły sposób ich obsługiwania. W wielu klientach poczty elektronicznej można teraz zauważyć, że kiedy użytkownik otrzymuje wiadomość w formacie HTML, jest pytany o to, czy chce pobrać obrazki. Jeśli wybierze się pobranie ich, jest bardzo prawdopodobne, że do serwera przekazane zostaną dane zawierające informacje o użytkowniku. Zazwyczaj jest to dość niegroźne i ma na celu powiadomienie aplikacji, ile osób otwarło określoną wiadomość, czy też którzy użytkownicy to zrobili. Ponownie mieści się to w obrębie Ajaksa, ponieważ pozwala na wykonywanie odwołań do serwera wykraczających poza model przesyłania żądania i otrzymywania odpowiedzi. W tym przypadku robi się to za pomocą atrybutu src znacznika . Zazwyczaj wyświetlany obrazek ma wielkość 1 piksel na 1 piksel, by użytkownik nie zauważył go na stronie. Serwer może następnie działać na bazie tych informacji i zapisać cookie na komputerze użytkownika. Oczywiście cookies cieszą się złą sławą, choć tak naprawdę nie robią żadnej krzywdy. Są to po prostu niewielkie pliki tekstowe, a informacje przez nie przechowywane są małe i nie są bezpośrednio związane z informacjami przechowywanymi na komputerze użytkownika. Zawierają unikalny identyfikator, który serwer może pobrać za każdym razem, gdy użytkownik powróci na stronę.
162
Ajax. Od podstaw Niedawno wybuchł głośny skandal, kiedy okazało się, że wyszukiwarki zapisywały wszystko, co wpisali do nich niektórzy użytkownicy. Dzięki rozpoznawaniu cookie za każdym razem, gdy użytkownik wykonywał zapytanie do wyszukiwarki, można było wydedukować informacje takie, jak to, gdzie mieszka i czym się zajmuje. W niektórych przypadkach informacje te można było połączyć z konkretną osobą. Technika opisana tutaj nie jest tak wścibska. Gdyby zastosowano ją w katalogu produktów, z grafiką przekazującą informacje znajdującą się na każdej stronie, można by było śledzić wzorce tego, jakie produkty ogląda użytkownik, dzięki czemu można by mu na przykład polecić powiązane produkty bądź też wskazać coś na bazie tego, co oglądają inni użytkownicy, których zainteresował ten sam produkt.
Pomysł Wzorzec działa w następujący sposób: 1.
Element opakowuje żądanie do serwera w atrybucie src, przekazując dodatkowe informacje dodane do łańcucha znaków zapytania.
2. Serwer przechowuje informacje i zapisuje unikalną informację przechowywaną
w cookie na kliencie. Wzorzec ten jest bardzo podobny w implementacji do przykładu z dynamicznym ładowaniem skryptu. Nie ma jednak tych samych wad i jest szeroko stosowany w przypadku użytkowników masowej korespondencji czy też na stronach, które śledzą zwyczaje swoich odwiedzających.
spróbuj sam Obrazki oraz cookies Tym razem utworzona zostanie strona naśladująca pojedynczą stronę z witryny księgarni internetowej. Kiedy użytkownik ogląda tę stronę, informacja o tym, co ogląda, przesyłana jest jako część obrazka do serwera. Serwer zapisuje następnie unikalny identyfikator do cookie i w oknie dialogowym wyświetla użytkownikowi informacje zawarte w cookie. 1.
Należy utworzyć stronę HTML i nazwać ją Catalogue.htm. W przykładzie tym potrzebnych będzie kilka obrazków. Można je pobrać wraz z kodami z serwera FTP pod adresem ftp://ftp.helion.pl/przyklady/ajaodp.zip.
Książka:
Autorzy: Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett
ISBN: 978-83-246-0567-5
Rozdział 4.
Techniki Ajaksa
163
Cena: 67.00
2. Należy utworzyć skrypt o nazwie ImageLoader.js i dodać do niego następujący kod: function createImage() { var bookid = document.getElementById("ISBN").innerHTML; var img = document.getElementById("secret"); img.src = "relayInformation.php?bookid=" + bookid; img.width = 0; img.height = 0; } function showCookie() { var cookie = getCookieInfo("AnonymousID"); alert(cookie); } function getCookieInfo(cookie) { RegularXp = "(?:; )?" + cookie + "=([^;]*);?"; var RegularXpExtract = new RegExp(RegularXp); if (RegularXpExtract.test(document.cookie)) { return decodeURIComponent(RegExp["$1"]); } else { return null; } }
3. Teraz czas utworzyć stronę po stronie serwera, która będzie ustawiała cookie. Jeśli
korzysta się z PHP, należy następujący kod zapisać jako relayInformation.php:
164
Ajax. Od podstaw Jeśli korzysta się ASP.NET, należy nazwać plik relayInformation.aspx i umieścić w nim następujący kod:
4. Pora otworzyć stronę Catalogue.htm w przeglądarce i kliknąć zawarty w niej
przycisk. Efekt będzie taki, jak na rysunku 4.10.
Rysunek 4.10. Cookie wyświetlone w przeglądarce
Rozdział 4.
Techniki Ajaksa
165
5. Należy zamknąć przeglądarkę i przejść ponownie do strony. Można zobaczyć, że kolejny raz dodała ona identyfikator książki bookid do cookie, co widać
na rysunku 4.11. Gdyby na stronie HTML zmieniono wartość na numer ISBN, przechowana zostałaby ta nowa wartość.
Rysunek 4.11. Dodanie bookid do cookie drugi raz
Jak to działa Powyższy przykład przedstawia, w jaki sposób można dynamicznie zmienić atrybut src obrazka, by wykonywał on wywołanie do serwera. Na początku strony ładuje się do niej funkcję createImage, a następnie odszukuje zawartość elementu zawierającą numer ISBN książki, który ma być przechowany w cookie, a także obrazek, który wyświetla obrazek onebyone.gif. var bookid = document.getElementById("ISBN").innerHTML; var img = document.getElementById("secret");
Dynamicznie zastępuje się atrybut src takim, który wskazuje na stronę po stronie serwera i przekazuje numer ISBN książki jako łańcuch znaków zapytania. Następnie ustawia się wysokość oraz szerokość obrazka na zero i dodaje się go do elementu body dokumentu. img.src = "relayInformation.php?bookid=" + bookid; img.width = 0; img.height = 0;
Kod po stronie serwera sprawdza po prostu istnienie cookie. Jeśli cookie istnieje, dodaje unikalny identyfikator (w ASP.NET generowany jest on za pomocą GUID, natomiast w PHP obsługa GUID nie jest wbudowana, dlatego na potrzeby niniejszego przykładu generowana jest losowa liczba) oraz numer ISBN książki:
166
Ajax. Od podstaw if ($_COOKIE[AnonymousID]) { $tempCookie = $_COOKIE["AnonymousID"]; setcookie("AnonymousID", $tempCookie."|BOOKID:".$_GET["bookid"], time()+3600); }
Jeśli cookie już istnieje, na jego końcu dodaje się informacje o książce. else { $random_id = (rand()%9999999); $tempCookie = "USERID:" .$random_id."|BOOKID:" . $_GET["bookid"]; setcookie("AnonymousID", $tempCookie."|BOOKID:".$_GET["bookid"], time()+3600); }
Następnie wykorzystano funkcję showCookie() do wyświetlenia treści. Można tu użyć technik ajaksowych do szybkiego pobrania wzorców przeglądania strony przez „anonimowego” użytkownika. Ponieważ GUID są zawsze unikalne, żadnym problemem nie byłoby przechowanie tych informacji w bazie danych. Z czasem można zgromadzić dane na temat tego, co robi użytkownik na stronie internetowej.
Zalety oraz wady Największym problemem jest to, że w aplikacji takiej jak klient poczty elektronicznej (bądź też niegdyś przeglądarka) użytkownik może wybrać niepobieranie obrazków. W programie Outlook jest to ustawienie domyślne. Istnieje również ograniczenie w wielkości informacji, jakie mogą być przechowywane w cookie, gdzie limitem jest około 4 kilobajtów (w zależności od tego, jak wiele z tej wielkości zajmuje unikalny identyfikator transakcji cookie). Powyższy przykład szybko napotkałby na problemy, choć w tym przypadku informacje przechowywane były w cookie tylko po to, by pokazać, jak można to zrobić. Inną wadą jest to, że rozwiązanie to znowu ograniczone jest wyłącznie do metody GET i nie może być używane w połączeniu z metodą POST. Czytelnik powinien mieć już rozeznanie w dużej liczbie popularnych technik, jakie można zastosować w celu utworzenia komunikacji między klientem a serwerem, a także wiedzieć, gdzie te techniki bądź narzędzia można zastosować.
Podsumowanie W niniejszym rozdziale omówiono pięć różnych technik ajaksowych. Najwięcej miejsca zajęło przedstawienie obiektu XMLHttpRequest, ponieważ jest on najchętniej wykorzystywany przez programistów. Pokazano również kilka przyczyn, z powodu których obiekt XMLHttpRequest może nie działać poprawnie. Powierzchownie omówiono najczęściej spotykane problemy i można było zauważyć, że często ich przyczyną są niezgodności pomiędzy przeglądarkami. Następnie przedstawiono cztery techniki alternatywne, dzięki czemu okazało się, że problemy tego typu występowały również w przypadku stosowania ukrytych ramek, ukrytych ramek typu iframe, dynamicznego ładowania skryptów oraz uprzedniego ładowania obrazków.
Rozdział 4.
Techniki Ajaksa
167
Wniosek wypływający z niniejszego rozdziału jest taki, że w przypadku technik ajaksowych często nie ma prostych skrótów. Choć wszystkie omówione techniki udostępniają programistom praktyczne i użyteczne sposoby komunikowania się z serwerem, okazuje się, że trzeba bardzo uważać na odpowiedzi otrzymywane w poszczególnych przeglądarkach. Obiekt XMLHttpRequest jest najbardziej elastycznym sposobem tworzenia aplikacji opartych na Ajaksie. Możliwe jest uzyskiwanie z samego obiektu większej liczby informacji dotyczących stanu przesyłanych i otrzymywanych danych, a dzięki programowi obsługi zdarzeń onreadystatechange można również pracować w sposób prawdziwie asynchroniczny. W dotychczasowych przykładach pojawiających się w książce często wykorzystywany był XML, dlatego pora przyjrzeć się samemu XML i jego wykorzystywaniu w Ajaksie. Kwestie te omówione są w rozdziale 5.
Ćwiczenie Sugerowane rozwiązania poniższego zadania znajduje się w dodatku A. 1.
Należy zmienić przykład z obiektem XMLHttpRequest, tak by działał on synchronicznie. W jaki sposób zmienia się jego zachowanie (o ile w ogólne się zmienia)? Dlaczego tak jest?
168
Ajax. Od podstaw
5
Praca z XML Kiedy wykorzystuje się obiekt XMLHttpRequest do wykonania żądania do serwera, serwer zwraca żądane dane w jednym z dwóch formatów: jako tekst bądź jako XML. Dane tekstowe to łańcuch znaków, który łatwo jest dodać do strony. Jest to jednak bardzo ograniczony format wymiany danych. Pomiędzy znakami nie ma elementów, typów danych czy innego rodzaju rozróżnienia. XML jest o wiele bardziej przydatnym formatem wymiany danych pomiędzy klientem (przeglądarką) a serwerem. XML jest językiem znaczników, który wykorzystuje zdefiniowane przez użytkownika znaczniki w określony sposób. Kiedy przeglądarka otrzymuje dokument XML z serwera w odpowiedzi na żądanie Ajaksa, konieczny jest jakiś sposób ekstrakcji danych XML oraz wyświetlenia ich. JavaScript może wykorzystywać węzły, właściwości węzłów oraz metody DOM do pobrania danych z dokumentu XML. Po ekstrakcji danych XML mogą one być wyświetlone na stronie za pomocą CSS oraz XSLT. W niniejszym rozdziale znajduje się przegląd podstawowych koncepcji związanych z XML, a także składni tego języka. Zaprezentowano również różne sposoby wykorzystywania JavaScriptu do ekstrakcji danych z dokumentu XML, przedstawiono techniki wyświetlania danych XML za pomocą CSS, a także używanie JavaScriptu do tworzenia dynamicznych stylów dla danych zwracanych z serwera. W niniejszym rozdziale omówione zostaną następujące kwestie:
podstawy XML (tworzenie znaczników, składnia XML, poprawne składniowo i strukturalnie dokumenty XML),
ekstrakcja danych XML za pomocą JavaScriptu (węzły, właściwości węzłów, metody DOM),
wykorzystywanie kaskadowych arkuszy stylów (CSS i dane XML, wykorzystywanie JavaScriptu z CSS).
170
Ajax. Od podstaw
Podstawy XML XML jest bardzo popularnym językiem wymiany danych. Dobrze nadaje się do organizowania danych oraz współdzielenia ich, ponieważ pozwala na klasyfikowanie danych, tworzenie określonych reguł dla ich formatu, a także zwracanie ich do różnych miejsc. Te same dane można na przykład wykorzystać w bazie danych, na stronie internetowej, a także w drukowanym formularzu. XML nie jest technologią własnościową i nie jest ograniczony do jakiejkolwiek jednej platformy czy urządzenia.
Tworzenie znaczników Kiedy buduje się nowy dokument XML od podstaw, tworzy się własny zbiór znaczników. Znaczniki te stanowią strukturę dokumentu. Dokument otrzymuje strukturę, by sprostać wyzwaniom związanym z wykorzystywaniem danych. Poniżej znajduje się przykład znaczników XML:
CS255 Informatyka JavaScript 3 Kowalski
W powyższym kodzie element classes zawiera wszystkie pozostałe elementy. Element class jest bezpośrednim potomkiem (dzieckiem) elementu classes i zawiera pięć dalszych elementów (classID, department, title, credits oraz instructor). Element zawiera znaczniki, a także dowolną zawartość. W powyższym kodzie jest znacznikiem otwierającym, natomiast element classID zawiera znaczniki otwierające oraz zamykające classID wraz z całą zawartością mieszczącą się pomiędzy nimi.
Nazwy znaczników XML muszą rozpoczynać się od litery bądź znaku „_”. Mogą zawierać litery, cyfry, kropki, myślniki bądź znaki _, jednak nie mogą zawierać spacji.
Składnia XML XML jest bardzo elastyczny, jednak składnia tego języka jest bardzo rygorystyczna. Wszystkie dokumenty XML muszą przestrzegać następujących podstawowych reguł:
Dokument XML rozpoczyna się od deklaracji XML:
Rozdział 5.
Praca z XML
Deklaracja ta jest pierwszym wierszem dokumentu i wskazuje na to, że jest to dokument XML. Deklaracja ta powinna również zawierać numer wersji oraz (co szczególnie ważne w przypadku polskich liter) kodowanie znaków, jak poniżej:
Dokument XML zawiera element główny, który zawiera wszystkie pozostałe elementy:
CS255 Informatyka JavaScript 3 Kowalski
W powyższym przypadku elementem głównym jest element classes. Element główny znany jest również pod nazwą elementu dokumentu (ang. document element).
Element XML musi zawierać znacznik otwierający oraz zamykający: JavaScript
Wyjątkiem od tej reguły jest element pusty. Elementy puste nie zawierają żadnej treści, choć mogą posiadać atrybuty, jak w poniższym kodzie:
Powyższy pusty element XML zawiera atrybut id o wartości 1428. Warto również zauważyć, że ten element zawiera też znak / przed nawiasem zamykającym znacznik — wskazujący, że jest to element pusty. Nie jest konieczne umieszczanie spacji przed znakiem ukośnika — procesor XML rozpozna, że chodzi o element pusty.
Znaczniki muszą być poprawnie zagnieżdżone:
Ostatni otwarty znacznik jest pierwszym znacznikiem do zamknięcia. Wcinanie kodu pozwala zachować czytelność hierarchii zagnieżdżenia.
Wszystkie wartości atrybutów muszą być umieszczone w cudzysłowach: ul. Piotrkowska
Bez względu na typ informacji zawartych w wartościach atrybutów wartości te muszą być umieszczone w apostrofach bądź cudzysłowach.
171
172
Ajax. Od podstaw Istnieje oczywiście wiele innych reguł dla dokumentów XML poza podstawowymi regułami składni przedstawionymi powyżej. Wszystkie szczegóły można znaleźć w specyfikacji XML 1.0 z W3C, dostępnej pod adresem www.w3.org/TR/xml/.
Dokumenty XML poprawne składniowo oraz strukturalnie Poprawny składniowo (ang. well-formed) dokument XML to taki, który przestrzega reguł składni XML. Poprawny strukturalnie (ang. valid) dokument XML to dokument poprawny składniowo, który przestrzega reguł określonych w definicji typu dokumentu (DTD, ang. Document Type Definition) bądź w dokumencie XML Schema. DTD oraz XML Schema udostępniają opisy dokumentów XML, czyli informacje takie, jak to, jakie elementy muszą zostać zawarte, jaka jest ich kolejność, ile razy każdy element może się pojawić w dokumencie, jakie są wszystkie atrybuty elementów, a także jaki typ danych może być umieszczony w elemencie. Dużą zaletą wykorzystywania XML do wymiany danych jest to, że opisy dokumentów XML (w szczególności XML Schema) mogą zawierać bardzo szczegółowe informacje o tym, jakie typy i formaty danych mogą być zawarte w dokumencie. Sprawdzanie poprawności dokumentów XML pozwala upewnić się co do jakości danych, które są zbierane, a także współdzielone z tymi dokumentami.
spróbuj sam Żądanie danych XML W poniższym przykładzie tworzy się obiekt XMLHttpRequest, który pobiera dokument XML (classes.xml) z serwera. Należy wpisać poniższy kod do edytora tekstu i zapisać go jako ch5_examp1.htm. Kiedy użytkownik kliknie przycisk Wykonaj żądanie, wyświetli się okno dialogowe widoczne na rysunku 5.1.
Żądanie XML
Żądanie XML
Należy wpisać poniższy kod do edytora tekstu i zapisać go jako classes.xml:
CS115 Informatyka 3 Mrozowski Podstawy programowania
CS205 Informatyka 3 Kowalski JavaScript
CS255 Informatyka 3 Bródka Java
By żądanie oparte na Ajaksie zadziałało, pliki ch5_examp1.htm oraz classes.xml muszą się znaleźć na serwerze. Należy skopiować oba pliki do podfolderu r05 w folderze BegAjax głównego katalogu serwera WWW (dla serwera IIS będzie to folder wwwroot, natomiast dla Apache — htdocs).
174
Ajax. Od podstaw
Rysunek 5.1. Okno dialogowe z ostrzeżeniem typu alert uzyskane dzięki kliknięciu przycisku Wykonaj żądanie
Jak to działa Strona ta zawiera formularz z przyciskiem podpisanym Wykonaj żądanie. Kiedy użytkownik kliknie przycisk, wywołana zostaje funkcja getDoc().
Do rejestracji zdarzenia kliknięcia wykorzystano tradycyjny model rejestracji zdarzeń, zamiast dołączać atrybut onclick do znacznika input.
Funkcja getDoc() wykorzystuje instrukcję if do sprawdzenia, czy przeglądarka obsługuje obiekt XMLHttpRequest w sposób bezpośredni. Jeśli tak jest, tworzony jest nowy obiekt XMLHttpRequest, który przechowywany jest w zmiennej o nazwie request. if (window.XMLHttpRequest) { request = new XMLHttpRequest(); }
Jeśli wykorzystywaną przez użytkownika przeglądarką jest Internet Explorer 5 bądź 6, tworzony jest nowy obiekt ActiveXObject, który jest następnie przechowywany w zmiennej request.
Rozdział 5.
Praca z XML
175
else if (window.ActiveXObject) { request = new ActiveXObject("Microsoft.XMLHTTP"); }
Internet Explorer 7 obsługuje obiekt XMLHttpRequest w sposób bezpośredni, przynajmniej jeśli chodzi o tworzenie nowych obiektów XMLHttpRequest bez używania ActiveX. Dodatkowe informacje na temat przeglądarki Internet Explorer 7 oraz obiektu XMLHttpRequest znajdują się w artykule IE7 XMLHttpRequest — Native or Not?, który można znaleźć na stronie http://ajaxian.com/archives/ie7-xmlhttprequest-native-or-not. Właściwości oraz metody obiektu XMLHttpRequest są nieco inne w różnych przeglądarkach. W przypadku przeglądarek opartych na silniku Mozilla (Mozilla, Firefox, Netscape Navigator), Safari oraz Internet Explorera — każda z nich obsługuje inne właściwości oraz metody. Więcej informacji na ten temat znajduje się w rozdziale 4. Metoda overrideMimeType obsługiwana jest w przeglądarkach z rodziny Mozilla. Metoda ta wykorzystywana jest do radzenia sobie z wszelkimi problemami związanymi z nagłówkiem Content-Type i zapewnia, że typ Mime dokumentów zwracanych z serwera równy będzie text/xml. Do sprawdzenia tego, czy metoda ta obsługiwana jest w przeglądarce, wykorzystano instrukcję if. Jeśli tak jest, metoda overrideMimeType zostaje zastosowana na obiekcie. if (request.overrideMimeType) { request.overrideMimeType("text/xml"); }
Jeśli obiekt został utworzony, metoda open obiektu XMLHttpRequest wykorzystana zostaje do zażądania danych z dokumentu XML classes.xml. Metoda ta posiada trzy parametry: metodę HTTP wykorzystywaną w żądaniu ("GET"), adres URL dokumentu ("classes.xml") oraz wartość typu Boolean równą true, wskazującą na to, że żądanie jest asynchroniczne. if(request) { request.open("GET", "classes.xml", true);
Metoda open może również zawierać dwa dodatkowe parametry z identyfikatorem użytkownika oraz hasłem, jeśli jest to wymagane dla połączenia z serwerem. Kiedy właściwość readyState obiektu XMLHttpRequest zmienia się (to znaczy, gdy dane zaczynają się pobierać), wywołana zostaje funkcja anonimowa. request.onreadystatechange = function() { if (request.readyState == 4 && request.status == 200) {
Jeśli właściwość readyState ma wartość równą 4, pobieranie zostało zakończone. Dodatkowe sprawdzanie, czy status ma wartość 200, wskazuje, że przetwarzanie żądania się powiodło. var xmlDocument = request.responseXML; alert('Pobrano dokument XML'); }
176
Ajax. Od podstaw Po zakończeniu pobierania wykorzystano właściwość responseXML do przechowania danych jako XML w zmiennej o nazwie xmlDocument. Okno dialogowe z ostrzeżeniem typu alert wyświetla się, by pokazać, że pobieranie dokumentu się powiodło. Metoda send wykorzystana jest do faktycznego wykonania żądania do serwera. Kiedy używa się metody GET, przesyła się wartość null. request.send(null);
Plik ten wykorzystuje kilka metod oraz właściwości obiektu XMLHttpRequest do wykonania żądania oraz pobrania danych XML z serwera. Metoda send wykorzystana zostaje do wykonania żądania i rozpoczęcia pobierania danych, metoda open służy do konfiguracji obiektu, natomiast właściwość responseXML zapisuje dane odpowiedzi z serwera jako XML. Jeśli chce się zobaczyć dane pobrane za pomocą responseXML, można w przeglądarce Internet Explorer skorzystać z jej właściwości xml, by zobaczyć dokument. Należy dodać poniższy kod bezpośrednio po pierwszym alert w funkcji anonimowej: alert(request.responseXML.xml);
Na rysunku 5.2 zaprezentowano dokument XML wyświetlony w oknie dialogowym z ostrzeżeniem typu alert w przeglądarce Internet Explorer.
Rysunek 5.2. Oglądanie dokumentu XML w przeglądarce Internet Explorer
W kolejnym podrozdziale omówione zostanie wykorzystywanie JavaScriptu do ekstrakcji danych z dokumentów XML zwracanych przez serwer.
Rozdział 5.
Praca z XML
177
Ekstrakcja danych za pomocą JavaScriptu Po pobraniu dokumentu XML z serwera kolejnym krokiem jest ekstrakcja danych XML z dokumentu za pomocą JavaScriptu. Można do tego wykorzystać węzły oraz właściwości węzłów bądź metody DOM. Poza ekstrakcją wartości elementów XML można również dokonywać ekstrakcji wartości atrybutów XML.
Wykorzystywanie węzłów JavaScript zawiera wbudowane właściwości, które można wykorzystać w dostępie do węzłów dokumentu XML. Właściwość documentElement można zastosować w celu uzyskania dostępu do elementu głównego dokumentu XML. Pozostałe właściwości węzłów obejmują inne relacje pomiędzy elementami, jak poniższe:
firstChild — węzeł będący pierwszym potomkiem,
lastChild — węzeł będący ostatnim potomkiem,
nextSibling — następny węzeł będący rodzeństwem,
previousSibling — poprzedni węzeł będący rodzeństwem,
childNodes — tablica węzłów potomnych.
Inne właściwości węzłów podają informacje o samym węźle:
nodeName — nazwa węzła,
nodeValue — wartość węzła,
nodeType — typ węzła.
Właściwość nodeType przydatna jest przy sprawdzaniu określonego typu węzła. Istnieje dwanaście typów węzłów, zaprezentowanych w tabeli 5.1. Więcej informacji na temat oglądania dokumentu jako drzewa przodków i potomków, a także postrzegania go jako drzewa węzłów znajduje się w rozdziale 2. By uzyskać dostęp do węzłów dokumentu XML, można skorzystać z relacji pomiędzy elementami. Jeśli chce się na przykład uzyskać dostęp do pierwszego kursu z dokumentu classes.xml, można wstawić dodatkowy kod do pliku ch5_examp1.htm, by przejść węzły dokumentu XML za pomocą związków między nimi. Można uzyskać dostęp do elementu głównego dokumentu classes.xml za pomocą właściwości documentElement: var rootNode = xmlDocument.documentElement;
xmlDocument to nazwa zmiennej zawierającej właściwość responseXML obiektu XMLHttpRequest. Węzłem głównym dokumentu rootNode jest element classes.
178
Ajax. Od podstaw
Tabela 5.1. Typy węzłów nodeType
Opis
1
Element
2
Atrybut
3
Tekst
4
Sekcja CDATA
5
Referencja do encji XML
6
Encja XML
7
Instrukcja przetwarzania XML
8
Komentarz XML
9
Dokument XML
10
DTD XML
11
Fragment dokumentu XML
12
Notacja XML
Można kontynuować przechodzenie dokumentu, wykorzystując relacje pomiędzy elementami: var classNode = rootNode.firstChild; var titleNode = classNode.lastChild; var titleText = titleNode.firstChild;
Węzłem classNode jest element class, pierwszy potomek elementu classes. Ostatnim potomkiem elementu class jest element title, przechowany w zmiennej titleNode. Pierwszym potomkiem elementu title jest węzeł tekstowy, który zawiera dane dotyczące tytułu kursu, przechowane w zmiennej titleText. Teraz można pobrać wartość węzła tekstowego z tytułem kursu za pomocą następującego kodu: var titleValue = titleText.nodeValue;
Powyższy kod działa w przeglądarce Internet Explorer, jednak w przeglądarkach z rodziny Mozilla białe znaki z dokumentów XML traktowane są jak węzły tekstowe. Kiedy uzyskuje się dostęp do firstChild dla elementu classes w przeglądarce tego typu, otrzymuje się węzeł tekstowy z białymi znakami zamiast elementu class. Można uwzględnić białe znaki i przeskoczyć je, wykorzystując do tego związki pomiędzy elementami. By uzyskać dostęp do elementu class, zamiast poniższego kodu: var classNode = rootNode.firstChild;
należy dodać właściwość nextSibling, by móc przejść nad węzłem tekstowym z białymi znakami: var classNode = rootNode.firstChild.nextSibling;
Można dodać kod usuwający wszystkie białe znaki z dokumentu XML, zamiast angażować się w coraz bardziej skomplikowane relacje pomiędzy elementami. Można również wybrać zupełnie inne podejście i uzyskiwać dostęp do elementów po ich nazwie, co jest omówione w kolejnym podrozdziale.
Rozdział 5.
Praca z XML
179
Dostęp do elementów XML po ich nazwie JavaScript zawiera metodę getElementsByTagName, którą można wykorzystać do ekstrakcji określonych elementów z dokumentu XML za pomocą nazwy tych elementów. Jeśli na przykład chce się dokonać ekstrakcji wartości pierwszego elementu title, należy skorzystać z nazwy tego elementu: var titleNode = xmlDocument.getElementsByTagName('title');
Ponieważ w dokumencie classes.xml istnieje więcej niż jeden element title, zmienna titleNode jest tablicą zawierającą kilka takich elementów. Należy użyć następującego kodu, by uzyskać dostęp do pierwszej wartości z tej tablicy: var firstTitle = titleNode[0];
Po uzyskaniu dostępu do elementu title można użyć firstChild oraz nodeValue w celu dokonania ekstrakcji wartości węzła tekstowego: var titleValue = firstTitle.firstChild.nodeValue;
Można wyświetlić tę wartość na stronie, dodając element div o identyfikatorze title i umieszczając go na stronie w miejscu, gdzie chce się wyświetlić tekst.
Należy utworzyć nowy element oraz węzeł tekstowy, by móc wyświetlić wartość tytułu wewnątrz elementu div: var myEl = document.createElement('p'); var newText = "Pierwszym kursem na liście jest " + titleValue + "."; var myTx = document.createTextNode(newText); myEl.appendChild(myTx); var course = document.getElementById('title'); course.appendChild(myEl);
Więcej informacji na temat wykorzystywania JavaScriptu do dodawania nowych elementów do istniejących stron znajduje się w rozdziale 2. Na rysunku 5.3 widać, że tytuł pierwszego kursu wyświetlany jest na stronie po kliknięciu przycisku przez użytkownika i przesłaniu żądania dokumentu XML do serwera.
Dostęp do wartości atrybutów Można również wykorzystać JavaScript w ekstrakcji wartości węzłów atrybutów z dokumentów XML. Węzły atrybutów zawarte są w węzłach elementów, dlatego należy rozpocząć od uzyskania dostępu do elementu zawierającego interesujący nas atrybut. Przykładowo w dokumencie classes.xml element credits zawiera atrybut o nazwie req, który wskazuje, czy kurs jest wymagany do ukończenia studiów na kierunku informatyka. Dostęp do elementu credits można uzyskać za pomocą metody getElementsByTagName: var creditStatus = xmlDocument.getElementsByTagName('credits');
180
Ajax. Od podstaw
Rysunek 5.3. Wyświetlanie tytułu pierwszego kursu
Następnie można skorzystać z właściwości attributes, by uzyskać dostęp do atrybutu. Ponieważ istnieje większa liczba elementów credits, zmienna creditStatus zawiera tablicę z kilkoma takimi elementami. By poznać wartość atrybutu dla trzeciego elementu credits z dokumentu, należy skorzystać z poniższego kodu: var creditAttr = creditStatus[2].attributes;
Metoda getNamedItem pozwala na dostęp do węzła atrybutu za pomocą nazwy tego atrybutu: var reqAttr = creditAttr.getNamedItem('req');
Wreszcie można użyć właściwości nodeValue do otrzymania wartości atrybutu req: var reqVal = reqAttr.nodeValue;
spróbuj sam Ekstrakcja wartości elementów oraz atrybutów w XML W tym przykładzie tworzy się obiekt XMLHttpRequest, który pobiera dokument XML. Następnie dokonuje się ekstrakcji wartości elementów oraz atrybutów XML z tego dokumentu i dodaje się je do istniejącej strony. Należy wpisać poniższy kod do edytora tekstu i zapisać go jako ch5_examp2.htm. Następnie należy skopiować ten plik do podfolderu r05 z folderu BegAjax w katalogu głównym serwera WWW (dla serwera IIS będzie to folder wwwroot, natomiast dla Apache — htdocs).
Rozdział 5.
Praca z XML
Sprawdzanie kursów
Sprawdzanie kursów
181
182
Ajax. Od podstaw
Na rysunku 5.4 zaprezentowano wyświetlanie elementów oraz atrybutów w przeglądarce Firefox.
Rysunek 5.4. Wyświetlanie elementów oraz atrybutów w przeglądarce Firefox
Jak to działa Plik jest dodatkiem do kodu utworzonego w poprzednim przykładzie. Tworzy się obiekt XMLHttpRequest, tak samo jak poprzednio. Po pobraniu dokumentu XML z serwera wywołuje się funkcję findClass, która dokonuje ekstrakcji danych o elementach oraz atrybutach XML i dodaje je do strony. if ((request.readyState == 4) && (request.status == 200)) { var xmlDocument = request.responseXML; findClass(xmlDocument); }
Funkcja ta rozpoczyna się od wyszukania elementów title w dokumencie XML za pomocą metody getElementsByTagName. function findClass(doc) { var titleNode = doc.getElementsByTagName('title');
Rozdział 5.
Praca z XML
183
Ponieważ elementów title jest więcej, zmienna titleNode zawiera tablicę z kilkoma elementami. Do wykonania iteracji po każdym elemencie tablicy titleNode wykorzystano pętlę for. Długość tej tablicy (titleNode.length) wykorzystano jako warunek tekstowy dla kontynuacji pętli for. for (i=0; i0"> Produkt | Ilość | Cena | |
| | PLN | |
|
Suma: | PLN | |
Twój koszyk jest pusty |
|
287
288
Ajax. Od podstaw 5. Teraz należy utworzyć arkusz stylów CSS o nazwie Cart.css i dodać do niego
poniższy kod: table { background-color: beige; border: 1px solid #e4ddca; } a img { border: 0px; } tr,td { font-family: Verdana; height: 15px; font-size: 75%; margin: 2px 0px 0px 0px; padding: 0px 0px 0px 5px; } .border { font-weight: bold; text-align: center; } .border2 { background: beige; } .head { font-family: Verdana; height: 15px; vertical-align: middle; background: #665D43; color: beige; font-weight: bold; }
6. Należy otworzyć stronę StaticXSLT.htm w przeglądarce i kliknąć odnośnik
Dodaj do koszyka z zakupami (rysunek 8.4). 7. Teraz należy przejść z powrotem do dokumentu Cart.xml, usunąć wszystkie
wiersze z wyjątkiem poniższych i zapisać plik:
8. Należy ponownie otworzyć stronę StaticXSTL.htm w przeglądarce i jeszcze raz
kliknąć odnośnik Dodaj do koszyka z zakupami (rysunek 8.5).
Rozdział 8.
XSLT oraz XPath
289
Rysunek 8.4. Otwarcie strony StaticXSLT.htm w przeglądarce i kliknięcie odnośnika Dodaj do koszyka z zakupami
Rysunek 8.5. Ponowne kliknięcie odnośnika Dodaj do koszyka z zakupami
290
Ajax. Od podstaw
Jak to działa Utworzono arkusz stylów, który wyświetla koszyk z zakupami jako komponent. Wykorzystano zarówno XSLT, jak i CSS, by koszyk wyglądał bardziej atrakcyjnie. Strona HTML zawiera odnośnik, który wywołuje funkcję GenerateCart() z kodu w JavaScripcie. Kod ten ładuje pliki XML oraz XSL, wykonuje na nich transformację i wypisuje wyniki z powrotem na stronie internetowej. Kod w JavaScripcie zawiera jeszcze kilka innych funkcji. Pierwsza z nich udostępnia szybki sposób załadowania dokumentu XML oraz arkusza stylów XSL działający we wszystkich przeglądarkach: function loadDocument(fileName) { var xmlDoc = window.ActiveXObject ? new ActiveXObject("MSXML2.DOMDocument.3.0") : document.implementation.createDocument("","",null); xmlDoc.async = false; xmlDoc.load(fileName); return xmlDoc; }
Jako parametr przekazuje się nazwę pliku i w zależności od tego, czy do przeglądania strony używa się przeglądarki Internet Explorer, czy Firefox, tworzy się albo obiekt MSXML2.DOMDocument, albo wbudowany w Firefoksa obiekt Document. Są one — tak jak poprzednio — ładowane synchronicznie. Funkcja getTransformedHTML() wykorzystywana jest do ekstrakcji przekształconego HTML. Implementacja w Firefoksie wymaga utworzenia instancji procesora i zaimportowania arkusza stylów, a następnie serializacji HTML do łańcucha znaków przed dodaniem go do strony. Wersja przeznaczona dla Internet Explorera pozwala na samą transformację węzła: function getTransformedHTML(xmlDoc, xslDoc) { var html = ""; if (window.XSLTProcessor) { var xsltProc = new XSLTProcessor(); xsltProc.importStylesheet(xslDoc); var fragment = xsltProc.transformToFragment(xmlDoc, document); html = new XMLSerializer().serializeToString(fragment); } else if (window.ActiveXObject) { html = xmlDoc.transformNode(xslDoc); } return html; }
Czas skoncentrować się na wykonywanej transformacji, ponieważ jest ona nieco bardziej skomplikowana niż poprzednie przykłady. Po deklaracji XML pojawia się element główny xsl:stylesheet, który zawiera wszystkie pozostałe elementy XSLT, a także element xsl:output określający dane wyjściowe jako HTML. Pierwszy szablon to ogólny szablon dopasowujący węzeł główny. Wewnątrz niego tworzy się tabelę HTML. W tabeli znajduje się wywołanie kolejnego szablonu, DisplayCart:
Rozdział 8.
XSLT oraz XPath
291
Tabela posiada odpowiednie wpisy w arkuszu stylów CSS. Jest to zbiór reguł, który wykorzystuje się do utworzenia niewielkiej beżowej ramki z obramowaniem o szerokości jednego piksela: table { background-color: beige; border: 1px solid #e4ddca; }
Szablon DisplayCart oraz arkusz stylów CSS wykonują całą pracę. Pierwszym elementem w szablonie DisplayCart jest nagłówek tabeli, element o klasie head, który w koszyku z zakupami ma ciemnooliwkowy kolor.
Koszyk z zakupami |
Element ten odnosi się do klasy head z arkusza stylów CSS: .head { font-family: Verdana; height: 15px; vertical-align: middle; background: #665D43; color: beige; font-weight: bold; }
Element head ustawia rozmiar czcionki, jej kolor, wysokość elementu, jego wyrównanie w pionie, kolor tła oraz tekstu, a także nadaje pogrubienie. W elemencie tym tworzony jest pojedynczy wiersz z pojedynczą komórką zawierającą tekst i obrazek koszyka z zakupami. W tej części nie ma żadnych deklaracji XSLT. W następnej części arkusza stylów XSLT zajęto się pomniejszym nagłówkiem znajdującym się poniżej głównego nagłówka tabeli wtedy, gdy jakieś produkty znajdują się w koszyku z zakupami.
Produkt | Ilość | Cena | |
292
Ajax. Od podstaw Nagłówek ten wyświetla słowa Produkt, Ilość oraz Cena w kolumnach tabeli, pod warunkiem że coś znajduje się w koszyku z zakupami. W celu sprawdzenia, czy w koszyku coś się znajduje, wykorzystano proste wyrażenie XPath. Wyrażenie to sumuje wszystkie liczby znajdujące się w elemencie należącym do elementu . Jeśli zwracana liczba jest większa od zera, można wyciągnąć wniosek, iż jakiś produkt znajduje się w koszyku, zatem należy wyświetlić nagłówek z opisem. Z punktu widzenia logiki, jeśli w koszyku znajduje się choć jeden produkt w ilości większej od zera, to koszyk nie może być pusty. Wiadomo, że jest to prawdą, ponieważ kiedy w koszyku nie ma produktów, nie ma również elementów oraz . Tworzenie wyrażeń XPath zostanie omówione bardziej szczegółowo po tym przykładzie. Po wyświetleniu obu nagłówków można przejść do wyświetlania każdego z produktów znajdujących się w koszyku z zakupami. Można tego dokonać dzięki użyciu pętli xsl:for-each. Do atrybutu select przypisuje się wyrażenie XPath, które odnosi się do każdego węzła książki z dokumentu XML. Wyrażenie to mówi, że dla każdego węzła należy wyświetlić pojedynczy wiersz tabeli z czterema kolumnami.
| | PLN | |
W pierwszej kolumnie wyświetlany jest tytuł książki. Można wykorzystać element xsl:value-of do wyświetlenia zawartości każdego z elementów . Ta komórka tabeli ma również przypisany styl (border2), który ustawia kolor tła komórki tabeli na beżowy. W drugiej kolumnie dzięki elementowi xsl:value-of wyświetlana jest ilość produktów, jaka znajduje się w koszyku. Ponownie komórce tej przypisany zostaje ten sam styl. W trzeciej kolumnie wyświetlana jest całkowita cena wszystkich egzemplarzy danego produktu znajdujących się w koszyku z zakupami. Wartość ta nie jest bezpośrednio dostępna w dokumencie XML, jednak można ją uzyskać w sposób pośredni. Należy wyświetlić całkowity koszt wszystkich egzemplarzy danej książki: gdyby zatem w koszyku znajdował się jeden egzemplarz pozycji Ajax. Zaawansowane programowanie, jego koszt byłby równy 67 PLN; dla dwóch egzemplarzy będzie to 134 PLN. Żeby to obliczyć, należy utworzyć wyrażenie XPath, które pobiera element Price i mnoży go przez wartość elementu Quantity. Do wyświetlenia końcowego rezultatu wykorzystano element xsl:value-of.
Rozdział 8.
XSLT oraz XPath
293
W ostatniej kolumnie wyświetla się odnośnik służący do usuwania elementów. Zamiast wyświetlać odnośnik tekstowy oraz by zachować koszyk jako niewielki i nierzucający się w oczy element strony, utworzono niewielki przycisk z krzyżykiem, który intuicyjnie wskazuje na to, że służy on do usuwania produktu z koszyka z zakupami. Element wywołuje funkcję AddRemoveItem z JavaScriptu. Na razie jednak odnośnik nie działa, ponieważ przykład ten nie został połączony z powrotem z główną aplikacją opartą na Ajaksie. Na dole koszyka z zakupami mieści się kolejna decyzja. W zależności od tego, czy w koszyku znajdują się jakieś produkty, decyduje się o tym, czy wyświetlić całkowity koszt wszystkich produktów, czy też komunikat wskazujący na to, że koszyk jest pusty. W tym celu wykorzystano konstrukcję xsl:choose. Wewnątrz instrukcji xsl:choose znajdują się dwie możliwe sytuacje. W elemencie xsl:when wykonuje się ten sam test, który wykonano w kodzie wcześniej w celu sprawdzenia wartości elementów . Jeśli elementy mają wartość większą od zera, wyświetla się wartość elementu Total z dokumentu XML.
Suma: | PLN | |
Twój koszyk jest pusty |
Przypadek xsl:otherwise obsługuje wszystkie pozostałe możliwości i wyświetla wiersz tabeli oraz pojedynczą komórkę zawierającą komunikat Twój koszyk jest pusty. Następnie — z powodów estetycznych —pod wierszem z sumą wyświetla się jeden pusty wiersz i zamyka szablon. Warto zauważyć, że do ustalenia sumy nie użyto XPath, choć można było tak zrobić. To, co zawarte jest w elemencie Price, nie jest wartością, z jakiej chce się skorzystać, a użycie XPath do czegoś więcej niż proste funkcje arytmetyczne może w XSLT okazać się trudne logistycznie (jak na przykład pomnożenie dwóch wartości pochodzących z innych tymczasowych wyrażeń XPath). Innymi słowy, kiedy pomnożono cenę przez ilość w celu otrzymania kosztu dla określonego wiersza tabeli, wynik nie został nigdzie przechowany, a pobranie go z XPath jest bardziej skomplikowane niż obliczenie go na serwerze i wpisanie wartości jako nowego elementu do dokumentu XML. Ponieważ niniejsze omówienie coraz bardziej dotyczy wyrażeń XPath, czas się przyjrzeć, w jaki dokładnie sposób się je tworzy i do czego się je wykorzystuje.
294
Ajax. Od podstaw
XPath oraz jego cel Język XPath wykorzystywany jest przede wszystkim do wybierania części dokumentu wejściowego do formatowania przez arkusz stylów XSLT. Dodatkowo język ten może też udostępniać funkcje arytmetyczne oraz formatowanie łańcuchów znaków, a także dodawać do wyrażeń warunki logiczne. Rola XPath jest w pewien sposób analogiczna do SQL, to znaczy tworzy się krótkie wyrażenia, które wykorzystywane są do pobierania danych z istniejącego źródła danych. Specyfikacja XPath, którą można znaleźć na stronie www.w3.org/TR/xpath, opisuje XPath jako język wyrażeń (czyli, innymi słowy, nie jest to pełny język programowania). XPath nie pozwala na tworzenie bądź przetwarzanie istniejących danych. Jest jedynie wykorzystywany do wykonywania zapytań do tych danych. XPath, podobnie jak XSLT, odgrywa istotną rolę w aplikacjach opartych na Ajaksie. Kod wykorzystywany w rozdziale 3. do wybierania części dokumentu XML za pomocą JavaScriptu oraz DOM miał następujący format: var header = serverResponse.getElementsByTagName("book"); ... spantag.innerHTML += " " + header[0].firstChild.text; spantag.innerHTML += " " + header[0].lastChild.text + " " + "Usuń przedmiot";
Byliśmy ograniczeni do wybierania elementów za pomocą metod getElementById bądź getElementsByTagName, a następnie wykorzystywania metod firstChild, lastChild oraz nextSibling w celu dotarcia do właściwych elementów za pomocą DOM. Choć metody te bez wątpienia działają dobrze, to przypominają one sytuację, w której, mając zasłonięte oczy, prosimy kogoś o kierowanie nami na trasie spaceru. Delikatnie mówiąc, może to być niezgrabne i mało wydajne. XPath jest bardzo przydatny do szybkiego izolowania i ustalania pewnych elementów (bądź podzbiorów elementów) wraz z wartościami, jakie one zawierają, a także zwracania tych rezultatów bezpośrednio do arkusza stylów XSLT zamiast do kodu w JavaScripcie czy też strony internetowej. To z kolei może sprawić, że strony będą tworzone szybciej, a wydajność aplikacji wzrośnie. XPath zawiera doskonałe możliwości zachowywania kontekstu tego, w jakim miejscu w dokumencie XML się znajdujemy w odniesieniu do innych elementów oraz węzłów. Tak jak w przypadku XSLT, niniejsze omówienie jest bardzo powierzchowne i demonstruje jedynie niewielki zbiór funkcji, co pozwoli zacząć pracę z tym językiem.
Podstawowe możliwości XPath W przykładach omawiających XSLT można już było zapoznać się z XPath. Jest to nieuniknione, ponieważ kiedy używa się jednego z tych języków, pojawia się konieczność stosowania drugiego. Kolejne przykłady także wykorzystują XSLT do zademonstrowania sposobu działania XPath.
Rozdział 8.
XSLT oraz XPath
295
Poniższe omówienie podzielone jest na dwie większe części. Pierwsza z nich obejmuje terminologię niezbędną do wykorzystywania wyrażeń XPath, natomiast druga pokazuje niektóre z najbardziej użytecznych funkcji XPath.
Wyrażenia XPath Dokumentacja MSDN (Microsoft Developer’s Network) dzieli wyrażenia XPath na pięć podstawowych typów:
kontekst bieżący,
węzeł główny dokumentu,
element główny dokumentu,
rekurencyjne schodzenie w dół drzewa,
określony element.
Warto krótko przyjrzeć się każdemu z nich. Do zaprezentowania przykładów warto zastosować poniższy dokument XML z koszykiem z zakupami, dzięki czemu łatwiej będzie sobie wszystko wyobrazić.
Ajax. Zaawansowane programowanie 1 Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett 978-83-246-0567-5 67.00
JavaScript dla webmasterów. Zaawansowane programowanie 2 Nicholas C. Zakas 83-246-0280-1 89.00
245.00
Do każdego z elementów z dokumentu XML można się odnieść pojedynczo za pomocą wyrażeń XPath.
Kontekst bieżący Kontekst bieżący to element, na który aktualnie się spogląda bądź z którym ma się właśnie do czynienia. Można się do niego odnieść za pomocą samej jego nazwy, co widać było we wcześniejszych kodach. Żeby na przykład użyć bieżącej wartości elementu Price należy wykorzystać następujący kod: Price
296
Ajax. Od podstaw To samo można uzyskać za pomocą składni z kropką oraz ukośnikiem: ./Price
Wyrażenie XPath służące do wybrania bieżącej wartości elementu Price w znaczniku xsl:value-of wyglądałoby na przykład następująco:
...
Gdyby w dokumencie XML znajdowało się wiele elementów Price, a wyrażenie zostałoby wywołane poza którąkolwiek z pętli xsl:for-each, zwróciłoby ono wartość pierwszego elementu Price, czyli 67.00. Gdyby zostało wywołane w konstrukcji xsl:for-each, zwróciłoby wartość każdego elementu po kolei, w zależności od tego, w którym miejscu pętli się jest.
Węzeł główny dokumentu By odnieść się do węzła głównego dokumentu (ang. document root), potrzebny jest pojedynczy ukośnik znajdujący się przed węzłem, co wskazuje, że jako bieżący kontekst chce się wybrać węzeł będący „korzeniem” drzewa. /cart
Powyższy kod zwróci element z elementem wraz z elementem potomnym , który z kolei zawiera węzeł tekstowy Ajax. Zaawansowane programowanie.
Element główny dokumentu By jako kontekst użyć element główny dokumentu (ang. root element), należy użyć wyrażenia XPath składającego się z pojedynczego ukośnika oraz znaku *. /*
Wyrażenie to w przykładowym dokumencie XML zwraca odniesienie do elementu , ponieważ jest on elementem głównym tego dokumentu.
Rekurencyjne schodzenie w dół drzewa Rekurencyjne schodzenie w dół drzewa (ang. recursive descent) może brzmieć dość niepokojąco, jednak działanie takie można już było zaobserwować w przypadku pętli xsl:for-each. Następujące wyrażenie wykorzystane zostało do wskazania każdego elementu z pętli: //book
Kod ten został wykorzystany do ujęcia zera lub większej liczby poziomów hierarchii w wyszukiwaniu i uzależniony jest od kontekstu, w jakim został użyty w dokumencie. W powyższym przypadku wyrażenie obejmuje wszystkie elementy book znajdujące się w dokumencie XML.
Rozdział 8.
XSLT oraz XPath
297
Wyrażenie tego typu można również wykorzystywać do izolowania grup elementów znajdujących się niżej w hierarchii dokumentu. Gdyby interesowały nas tylko elementy każdej książki, można by było zastosować następujący kod: //book/Price
Wyrażenie to można na przykład wstawić do xsl:if w celu sprawdzenia każdego elementu i przekonania się, czy jest on większy od zera:
Określone elementy Jeśli chce się wykorzystać XPath do wybrania określonego elementu bądź elementów, można zastosować kod zaprezentowany we wcześniejszych przykładach. Jeśli chce się wybrać określony element, to w przypadku, gdy może wystąpić jeden taki element bądź większa ich liczba, należy skorzystać z poniższego wyrażenia: book/Price
Każdy z tych elementów ma być użyty w kontekście atrybutu znacznika XSLT.
Funkcje XPath Poza składnią wykorzystywaną do tworzenia wyrażeń XPath zawiera również kilka funkcji. XPath często wykorzystuje się właśnie ze względu na te funkcje. Warto przyjrzeć się najczęściej wykorzystywanym.
Funkcja number Funkcja number wykorzystywana jest do konwersji wartości na liczbę zmiennoprzecinkową podwójnej dokładności, odpowiednik typu danych double. Jest ona przydatna w sytuacji, gdy posiada się zmienną o wartości liczbowej (na przykład wartości typu Boolean), która jednak nie jest natychmiast rozpoznawalna jako liczba. Czasami można zastosować to jako zabezpieczenie w czasie awarii, kiedy nie jest się w stu procentach pewnym formatu danych zwracanych w dokumencie XML. Można na przykład wykorzystać tę funkcję w następujący sposób w celu potwierdzenia, czy element Price zwrócił wartość liczbową. Funkcja number zwróci wartość NaN (Not a Number), jeśli wartość ta nie jest liczbą.
Następnie wyświetli się element Price tylko wtedy, gdy dla ceny została podana jakaś wartość. Jeśli na przykład jakaś książka została usunięta, może nie mieć podanej ceny, a dzięki funkcji number możliwe będzie wyświetlenie komunikatu: „Niepoprawne dane” czy „Książka niedostępna”. W XPath do konwersji wyniku funkcji number na łańcuch znaków służy funkcja string. Istnieje również podobna funkcja boolean, która dokonuje konwersji wyniku wyrażenia na wartość typu Boolean.
298
Ajax. Od podstaw
Funkcja position Funkcję position można wykorzystać do sprawdzenia, czy jest się na początku jakiejś sekwencji, czy też na jej końcu. Funkcja ta zwraca pozycję węzła kontekstowego w zbiorze węzłów kontekstu. Choć funkcja position ma wiele zastosowań, jednym z bardziej przydatnych jest użycie jej wewnątrz pętli do sprawdzenia, w którym miejscu pętli się jest. Jeśli chce się na przykład dodać serię słów (takich, jak w menu) rozdzielonych znakiem |, można utworzyć funkcję XSLT, która sprawdza, czy bieżący kontekst w pętli nie był ostatnim, a następnie wyświetla znak | — jak w kodzie poniżej:
|
Funkcja count Funkcja count pobiera jako argument zbiór węzłów i zwraca liczbę węzłów z tego zbioru. Gdyby na przykład chciano zwrócić liczbę elementów book w dokumencie, należałoby wykorzystać następujący kod:
Formatowanie łańcuchów znaków A oto znany prawie wszystkim sekret: XPath nie jest jednym z najlepszych języków programowania, jeśli chodzi o formatowanie łańcuchów znaków. Lepiej będzie spróbować wykonać to formatowanie gdzieś indziej, na przykład na serwerze, o ile tylko jest to możliwe. Większość możliwości XPath służących do odnajdywania części łańcuchów znaków sprowadza się do jednej funkcji — substring, co może sprawić, że próba podziału łańcuchów znaków na części może wydawać się skomplikowaną łamigłówką logiczną. Poniżej znajdują się najczęściej wykorzystywane wyrażenia XPath działające na łańcuchach znaków:
substring — zwraca część wartości łańcucha znaków,
concat — jako argumenty przyjmuje dwa bądź większą liczbę łańcuchów znaków i łączy je ze sobą w procesie konkatenacji.
W XPath 2.0 wprowadzono również funkcję replace(), jednak obecnie żadna współczesna przeglądarka nie obsługuje tego standardu. W celu utworzenia podłańcucha znaków z łańcucha concat zawierającego jedynie słowo cat należy skorzystać z poniższego kodu: substring("concat", 4,3)
Rozdział 8.
XSLT oraz XPath
299
Funkcje arytmetyczne W wyrażeniach XPath można korzystać z normalnych operatorów arytmetycznych, takich jak plus, minus, znak operatora mnożenia czy dzielenia, jak również z nawiasów, które wskazują kolejność wykonywania poszczególnych działań. Dodatkowo poniżej znajduje się lista niektórych bardziej przydatnych funkcji arytmetycznych z XPath:
sum — zwraca sumę liczb ze zbioru węzłów liczb,
round — zaokrągla liczbę do najbliższej jej liczby całkowitej (na przykład z 3.3 uzyskuje się 3, natomiast z 4.7 — 5),
ceiling — zaokrągla liczbę do najbliższej większej liczby całkowitej (na przykład z 1.2 uzyskuje się 2),
floor — zaokrągla liczbę do najbliższej mniejszej liczby całkowitej (na przykład z 3.9 uzyskuje się 3).
Funkcje arytmetyczne są dość oczywiste. Można zastanowić się nad poniższym użyciem funkcji sum: sum (//Price)
Wyrażenie to zwróci sumę elementów Price z dokumentu XML. Funkcje te można zastosować na zawartości elementów. Jeśli na przykład chce się zaoferować zniżkę użytkownikom, którzy wydali ponad sto złotych, można skonstruować poniższą instrukcję XSLT, która zajmie się taką możliwością:
...
W XPath 2.0 dodano następujące funkcje:
max — zwraca wartość maksymalną ze zbioru węzłów,
min — zwraca wartość minimalną ze zbioru węzłów,
avg — zwraca wartość średnią ze zbioru węzłów.
Funkcje te nie są jednak obsługiwane w przeglądarce Internet Explorer.
Funkcje logiczne Operatory logiczne w XPath to po prostu angielskie słowa reprezentujące dane działania, natomiast wartości logiczne same są słowami.
not — zwraca true, jeśli wartość jest false i odwrotnie,
true — zwraca true,
false — zwraca false.
300
Ajax. Od podstaw Operatory logiczne w XPath wykorzystywane są w ten sam sposób jak w normalnych językach programowania — służą do łączenia serii wyrażeń w celu umożliwienia bardziej złożonych zbiorów zapytań.
and — łączy wyrażenia i oznacza „i”,
or — łączy wyrażenia i oznacza „lub”.
Gdyby na przykład chciano dodać następną zniżkę klientom, którzy zakupili więcej niż trzy osobne produkty oraz książki o cenie przekraczającej sto złotych, poniższa instrukcja XSLT łączy te dwa wyrażenia:
...
Wykonywanie zapytań w dokumentach XML za pomocą XPath Przedstawiono już spory zbiór funkcji XPath, które można wykorzystywać. Warto zatem utworzyć krótki przykład, w którym XPath wykona za nas jakieś zadania.
spróbuj sam Wykorzystywanie XPath do wykonywania zapytań do dokumentu XML W tym krótkim przykładzie XPath wykorzystany zostanie do szybkiego przetworzenia wyników zawodników startujących w biegu (na przykład obliczenia średniego czasu zawodników oraz upewnienia się, że dane są dobrze sformatowane i poprawnie wyświetlają czasy). By wszystko nieco bardziej skomplikować, wartości podawane są jako całkowita liczba sekund dla każdego zawodnika. Może się to wydawać nieco sztuczne, jednak pozwala zastosować dodatkowe przetwarzanie z użyciem XPath w celu wyświetlenia danych w pożądanej formie. 1.
Należy utworzyć nowy plik HTML o nazwie XPath.htm i dodać do niego poniższy kod:
Przykład użycia XPath
Rozdział 8.
XSLT oraz XPath
2. Należy utworzyć plik w JavaScripcie o nazwie XPath.js i dodać do niego
poniższy kod: function loadDocument(fileName) { var xmlDoc = window.ActiveXObject ? new ActiveXObject ("MSXML2.DOMDocument.3.0") : document.implementation. createDocument("","",null); xmlDoc.async = false; xmlDoc.load(fileName); return xmlDoc; } function getTransformedHTML(xmlDoc, xslDoc) { var html = ""; if (window.XSLTProcessor) { var xsltProc = new XSLTProcessor(); xsltProc.importStylesheet(xslDoc); var fragment = xsltProc.transformToFragment(xmlDoc, document); html = new XMLSerializer().serializeToString(fragment); } else if (window.ActiveXObject) { html = xmlDoc.transformNode(xslDoc); } return html; } function Transform() { var xmlDoc = loadDocument("runners.xml"); var xslDoc = loadDocument("runners.xsl"); document.getElementById("example").innerHTML = getTransformedHTML(xmlDoc, xslDoc); }
3. Należy utworzyć nowy plik XML o nazwie runners.xml:
Amadeusz Długonogi 3274
Aleksander Szybki 3314
Edward Biegacz 3305
Euzebiusz Maratończyk 3256
301
302
Ajax. Od podstaw
Bonifacy Wolny 3301
4. Należy utworzyć arkusz stylów XSLT o nazwie runners.xsl i dodać do niego
poniższy kod:
Miejsce | Imię i nazwisko | Czas |
| | . 0 |
Średni czas: | | . Rozdział 8. XSLT oraz XPath 303 0 |
5. Należy otworzyć stronę XPath.htm w przeglądarce (rysunek 8.6).
Rysunek 8.6. Strona XPath.htm w przeglądarce
Jak to działa Kody w HTML oraz JavaScripcie wykorzystane do utworzenia strony i wykonania transformacji są takie same jak w poprzednim przykładzie, więc nie ma sensu ich omawiać. Lepiej przyjrzeć się arkuszowi stylów XSLT z punktu widzenia XPath. Rozpoczyna się od użycia zapisu wskazującego na rekurencyjne schodzenie w dół hierarchii w celu wybrania każdego elementu z dokumentu XML. XPath nie potrafi sortować wyników, dlatego konieczne będzie zapożyczenie znacznika xsl:sort z XSLT i wykorzystanie elementu totalseconds:
304
Ajax. Od podstaw W pierwszej kolumnie chcemy wyświetlić informację o miejscu zdobytym w zawodach. Informacji tych nie ma jednak w dokumencie XML. Wiadomo, że posortowanie wyników wyświetli biegaczy w kolejności w pętli xsl:for-each, dlatego wystarczy zastosować funkcję XPath position() do zwrócenia numeru miejsca z pętli: |
W drugiej kolumnie wykorzystano zapis z XPath służący do wybrania kontekstu bieżącego w celu wyświetlenia wartości elementu name. Wartość ta będzie inna dla każdego elementu w dokumencie. |
W trzeciej kolumnie wyświetlany jest czas zawodnika. Pokazanie czasu zawodnika w postaci całkowitej liczby sekund nie jest oczywiście zbyt przydatne, dlatego konieczne będzie wprowadzenie zmian, dzięki którym wynik wyświetlany będzie w minutach oraz sekundach. Te dwie wartości należy uzyskać osobno. By otrzymać liczbę minut, należy podzielić element totalseconds przez sześćdziesiąt i wykorzystać funkcję floor do uzyskania najbliższej mniejszej liczby całkowitej. W większości języków programowania znajduje się operator odpowiedzialny za to zadanie i faktycznie w XPath 2.0 wprowadzono operator idiv. W przeglądarce Internet Explorer skorzystanie z tego rozwiązania jest niemożliwe. Drugą wartością są sekundy, będące po prostu pozostałą liczbą sekund obliczoną za pomocą operatora mod. Pojawia się jeszcze jeden problem: kiedy liczba sekund będzie mniejsza niż dziesięć, można otrzymać czas taki, jak 54.9 — zamiast 54.09. Można sobie z tym poradzić, sprawdzając, czy reszta z dzielenia totalseconds przez sześćdziesiąt jest mniejsza bądź równa dziewięć. Jeśli tak jest, dodaje się dodatkowe zero. W przeciwnym razie nie robi się nic. . 0 |
XPath 2.0 udostępnia również funkcję avg, jednak ponieważ żadna współczesna przeglądarka jej nie obsługuje, nie mamy do niej dostępu. Oznacza to, że do obliczenia średniej niezbędne będzie nieco dodatkowego kodu. Średnia obliczana jest dzięki pobraniu wartości każdego elementu totalseconds i podzieleniu go przez liczbę zawodników. Liczbę zawodników
Rozdział 8.
XSLT oraz XPath
305
można uzyskać za pomocą funkcji count() z XPath, która służy do zliczania wszystkich elementów. Za każdym razem używa się zapisu z // w celu zidentyfikowania wszystkich elementów z dokumentu. Kiedy już ma się średnią wartość totalseconds dla biegaczy, można wykorzystać zaprezentowany wyżej proces do ekstrakcji minut oraz sekund, a następnie wyświetlenia ich w tabeli. Średni czas: | | . 0 |
Jak widać, ograniczenia XPath oznaczają, że nawet tak proste funkcje, jak wyświetlanie czasu, mogą być dość kłopotliwe. Czasami jednak programiści nie mają wyboru — otrzymują dane XML i muszą sobie z nimi poradzić. W takich przypadkach mogą oni przetworzyć dane w XSLT bądź w JavaScripcie i często wielu z nich optuje za wykorzystaniem XPath do przetwarzania danych w XSLT.
Ulepszenie przykładu z koszykiem z zakupami, tak by używał on XSLT oraz Ajaksa Teraz można już połączyć te języki w przykładzie z koszykiem z zakupami, by działał on jak prawdziwa aplikacja pozwalająca na dodawanie oraz usuwanie produktów, wykorzystująca arkusz stylów XSLT oraz reguły CSS w celu nadania koszykowi ciekawszego wyglądu.
spróbuj sam Dodanie interaktywności do koszyka z zakupami W niniejszym przykładzie połączony zostanie kod wykorzystany w rozdziale 3. w oryginalnym koszyku z zakupami oraz kod poprawiony zaprezentowany wcześniej w niniejszym rozdziale, dzięki czemu powstanie spójnie działająca aplikacja oparta na Ajaksie. 1.
Należy otworzyć plik Catalogue1.htm utworzony w rozdziale 3. i zmienić w nim wyróżnione wiersze (jeśli Czytelnik nie utworzył jeszcze tego kodu, nie ma się co martwić, bo cała jego zawartość znajduje się poniżej).
306
Ajax. Od podstaw
Książka:Ajax. Zaawansowane programowanie
Autor: Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett
ISBN: 978-83-246-0567-5
Cena: 67.00
Dodaj do koszyka
2. Należy utworzyć następujący plik ShoppingCart.js. Warto zwrócić uwagę na to, że używamy tej wersji, ponieważ wykorzystuje ona metodę POST do przesyłania
danych. By koszyk z zakupami miał pożądane możliwości, w tym przypadku lepsze będzie skorzystanie właśnie z metody POST. var xHRObject = false; if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); } else if (window.XMLHttpRequest) { xHRObject = new XMLHttpRequest(); } function getBody(action) { var argument = "book="; argument += encodeURI(document.getElementById("book").innerHTML); argument += "&ISBN="; argument += encodeURI(document.getElementById("ISBN").innerHTML); argument += "&authors="; argument += encodeURI(document.getElementById("authors").innerHTML); argument += "&price="; argument += encodeURI(document.getElementById("price").innerHTML); argument += "&action="; argument += encodeURI(action); return argument; }
Rozdział 8.
XSLT oraz XPath
function getData() { if ((xHRObject.readyState == 4) &&(xHRObject.status == 200)) { if (window.ActiveXObject) { // Załadowanie XML var xml = xHRObject.responseXML; // Załadowanie XSL var xsl = new ActiveXObject("Microsoft.XMLDOM"); xsl.async = false; xsl.load("Cart.xsl"); // Transformacja var transform = xml.transformNode(xsl); var spanb = document.getElementById("cart"); spanb.innerHTML = transform; } else { var xsltProcessor = new XSLTProcessor(); // Załadowanie XSL xslStylesheet = document.implementation.createDocument("", "doc", null); xslStylesheet.async = false; xslStylesheet.load("Cart.xsl"); xsltProcessor.importStylesheet(xslStylesheet); // Załadowanie XML xmlDoc = xHRObject.responseXML; // Transformacja var fragment = xsltProcessor.transformToFragment(xmlDoc, document); document.getElementById("cart").innerHTML = new XMLSerializer(). serializeToString(fragment); } } } function AddRemoveItem(action) { var book = document.getElementById("book").innerHTML; var bodyofform = getBody( action); xHRObject.open("POST", "cartdisplay.php", true); xHRObject.setRequestHeader("Content-Type", "application/x-www-formurlencoded"); xHRObject.onreadystatechange = getData; xHRObject.send(bodyofform); }
307
308
Ajax. Od podstaw 3. Następnie należy otworzyć kod po stronie serwera cartdisplay.aspx i dodać do niego następującą przestrzeń nazw oraz następujące zmiany do funkcji toXML:
4. W PHP będą to poniższe zmiany:
5. Należy otworzyć stronę Catalogue1.htm w przeglądarce i kliknąć odnośnik
Dodaj do koszyka (rysunek 8.7).
Rysunek 8.7. Otwarcie strony Catalogue1.htm w przeglądarce i kliknięcie Dodaj do koszyka 6. Jeśli ponownie kliknie się odnośnik Dodaj do koszyka, suma zamówionych
produktów zwiększy się o jeden. Jeśli następnie kliknie się widoczny na rysunku krzyżyk, wszystkie produkty zostaną usunięte, jak widać na rysunku 8.8.
311
312
Ajax. Od podstaw
Rysunek 8.8. Rezultat kliknięcia krzyżyka
Jak to działa W niniejszym przykładzie nie wprowadzono niczego dramatycznie nowego. Wykorzystano tylko istniejący już kod do udostępnienia koszyka z zakupami i sprawiono, że działa on w sposób dynamiczny, zamiast wykorzystywać go jako stronę statyczną. Dodano skrypt wykonujący transformację w przeglądarkach Internet Explorer bądź Mozilla z poprzednich przykładów koszyka z zakupami, a następnie dołączono do niego nowy parametr o nazwie action. Ten dodatkowy parametr wykorzystywany jest do ustalenia, czy zamierza się dodać produkty do koszyka z zakupami, czy też je usunąć. Ponieważ dane z obiektu XMLHttpRequest przekazuje się za pomocą metody POST, należy opakować ten dodatkowy parametr w formularzu za pomocą funkcji getBody. function getBody(action) { var argument = "book="; argument += encodeURI(document.getElementById("book").innerHTML); argument += "&ISBN="; argument += encodeURI(document.getElementById("ISBN").innerHTML); argument += "&authors="; argument += encodeURI(document.getElementById("authors").innerHTML); argument += "&price=";
Rozdział 8.
XSLT oraz XPath
313
argument += encodeURI(document.getElementById("price").innerHTML); argument += "&action="; argument += encodeURI(action); return argument; }
Wymaga to dodania dwóch dodatkowych wierszy do kodu oraz przekazania wartości parametru action do funkcji. Jeśli użytkownik kliknął odnośnik Dodaj do koszyka, wtedy parametr ten zawiera słowo Add. W kodzie po stronie serwera dodano dodatkowy element do dokumentu XML w celu odnotowania sumy zakupów. Oznacza to, że kiedy tworzy się dokument XML, należy się upewnić, że węzeł ten zostanie utworzony i że poprawnie doda się ceny produktów do tego węzła. W ASP.NET wymaga to utworzenia zmiennej będącej liczbą dziesiętną, w której przechowywana będzie ta suma, a także utworzenia elementu. decimal total = 0; XmlNode TotalNode = XmlDoc.CreateElement("Total");
Następnie w pętli dodaje się cenę pomnożoną jako liczbę egzemplarzy każdego z produktów: total += decimal.Parse(price, new CultureInfo("en-US")) * quantity;
Ponieważ niektóre kraje używają liczb dziesiętnych w określonym formacie, dodano informację na temat kultury en-US, by wymusić stosowanie kropki jako symbolu ułamka dziesiętnego. Wreszcie na końcu pętli można dodać całkowitą wartość do elementu, a także dodać nowy element total do dokumentu XML. TotalNode.AppendChild(XmlDoc.CreateTextNode(total.ToString())); mainNode.AppendChild(TotalNode);
Jest to odsyłane jako część dokumentu XML. Obiekt XMLHttpRequest otrzymuje odpowiedź i udostępnia dokument XML za pomocą responseXML. Do wygenerowania koszyka z zakupami oraz jego zawartości można wykorzystać technologie XSLT oraz XPath.
Podsumowanie Niniejszy rozdział był przyspieszonym kursem dwóch języków — XSLT oraz XPath. Na ten temat napisano już wiele książek, dlatego nic dziwnego, że w rozdziale tym pominięto sporo szczegółów. XSLT jest językiem transformacji jednego dokumentu XML na drugi. XPath jest podjęzykiem, który pozwala wykonywać zapytania oraz odszukiwać określone węzły bądź elementy w dokumencie.
314
Ajax. Od podstaw Języki te zostały wykorzystane w celu wykonania transformacji dokumentów XML oraz zwrócenia danych wyjściowych do właściwości responseXML obiektu XMLHttpRequest. XSLT wykorzystuje elementy, jednak posiada strukturę pseudojęzyka programowania, gdyż zawiera możliwość dokonania wyboru dzięki xsl:if, wykonania pętli za pomocą xsl:for-each oraz ponownego wykorzystywania szablonów dzięki znacznikom xsl:template. XPath nie jest tak naprawdę językiem jako takim i udostępnia możliwość wykonywania zapytań do atrybutów XSLT, które mogą być wykorzystywane do odnajdywania określonej zawartości dokumentów jako alternatywa dla używania DOM. Powodem wykorzystywania XSLT oraz XPath w aplikacjach opartych na Ajaksie jest to, że technologie te pomagają zachować rozdzielenie projektu oraz zawartości, zwracają zawartość w postaci XML (czyli doskonale nadają się do pracy z obiektem XMLHttpRequest) i udostępniają prostszy (oraz bardziej efektywny) sposób wyszukiwania oraz wyświetlania wybranych części dokumentu XML na stronie internetowej.
Ćwiczenia Sugerowane rozwiązania niniejszych zadań znajdują się w dodatku A. 1.
Należy utworzyć arkusz stylów XSLT, który pobiera listę hoteli z Example.xml i wyświetla ją nie w tabeli, ale jako listę elementów.
2. Należy zmodyfikować arkusz stylów XSLT koszyka z zakupami w taki sposób,
by wyświetlał on również numer ISBN książki.
9
Wzorce W programowaniu ważną zasadą jest tworzenie kodu, który można będzie wykorzystać w aplikacji ponownie. Kiedy odsunie się kod na chwilę od siebie i spróbuje na niego spojrzeć z szerszej perspektywy, można zauważyć, że powtarza się nie tylko niewielkie części kodu. Powtarzalne są również typy problemów, jakie kod ma rozwiązywać. Jak często programista musi tworzyć koszyk z zakupami bądź implementować algorytm służący do bezpiecznego logowania się? Zadania takie, jak sprawdzanie poprawności formularzy, są codziennymi elementami życia programisty i nie da się ich obejść. Problemem jest jednak to, że zazwyczaj nie da się wziąć kodu z jednej aplikacji i wkleić go do drugiej. Jeśli cały tydzień pracuje się nad kodem dla księgarni, a następny tydzień nad kodem dla księgowych, części tego kodu będzie pewnie można przenieść, jednak w dużej mierze będzie to niemożliwe. Obie strony mogą wymagać sprawdzania poprawności formularzy, obie mogą zawierać elementy takie, jak listy oparte na przeciąganiu oraz upuszczaniu i w obu przypadkach dobrze by było w elegancki sposób radzić sobie z błędami. W programowaniu rozwiązanie często spotykanego problemu nazywane jest wzorcem bądź wzorcem projektowym (ang. design pattern). Wzorzec jest szablonem, który określa sposób radzenia sobie z jakimś problemem. Jak przedstawiono w rozdziale 1., samo to, że można używać Ajaksa na każdej stronie internetowej, nie oznacza, że tak właśnie należy robić. Jak w przypadku każdej innej dyscypliny, od sportu po inżynierię, zawsze istnieje dobry sposób zrobienia czegoś, a także zły. W sporcie, jeśli zawodnik dobrze się nie rozgrzeje, a później nie ochłonie, bądź też jeśli nie będzie przestrzegał odpowiedniego rygoru treningowego, istnieje duże prawdopodobieństwo, że nie tylko nie stanie się bardziej sprawny i wysportowany, ale może nawet odnieść groźną kontuzję. W przypadku inżynierii, jeśli nie będzie się przestrzegało określonych zasad budowy mostów, istnieje niebezpieczeństwo, że taki most się zawali (bądź też będzie się kiwał na boki, jak to było swego czasu w przypadku pewnego sławnego mostu w Londynie!). W przypadku aplikacji opartych na Ajaksie, jeśli nie przestrzega się określonych wzorców, prawdopodobne stanie się tak, że aplikacja nie będzie działała zgodnie z zamierzeniami autora — o ile w ogóle będzie działała.
316
Ajax. Od podstaw Choć niektórzy ludzie nie zawsze lubią postępować zgodnie z instrukcjami i uczyć się na błędach popełnianych przez inne osoby, wynajdywanie koła na nowo nie ma sensu, szczególnie w przypadku czegoś tak nużącego, jak sprawdzanie poprawności formularzy. Gdyby istniał lepszy sposób zrobienia tego, ktoś na pewno już by go wymyślił! W niniejszym rozdziale przedstawiono zatem pięć prostych wzorców projektowych, w których można zastosować Ajaksa, a do każdego z nich utworzono przykładowy kod. W niniejszym rozdziale omówiono następujące kwestie:
podstawy wzorców projektowych,
wzorzec projektowy służący do sprawdzania poprawności formularzy,
wzorzec służący do wyświetlania dodatkowych informacji po najechaniu myszą na element,
wzorzec służący do ciągłego odświeżania strony,
listy opierające się na przeciąganiu oraz upuszczaniu,
wzorzec służący do obsługi błędów.
Podstawy wzorców projektowych Wzorce (lub wzorce projektowe) są wypróbowanymi i przetestowanymi technikami bądź sposobami podejścia do różnych często występujących problemów. Jedna z pierwszych prób udokumentowania wzorców projektowych podjęta została przez programistę Michaela Mahemoffa na stronie internetowej www.ajaxpatterns.org1. Jak w przypadku wszystkich inicjatyw w Internecie, pojawiły się tysiące naśladowców, dzięki czemu można obecnie znaleźć wiele stron z podobnymi wzorcami, a każda z nich udostępnia bardzo podobny (o ile nie identyczny) zbiór wzorców. W niniejszym rozdziale zastosowano inne podejście, niż miało to miejsce w przypadku pozostałych części książki. Każdy problem omawiany jest oddzielnie. Wyjaśnione zostanie, w jaki sposób Ajax może się przyczynić do rozwiązania danego problemu, a także jak należy zaimplementować dane rozwiązanie. Istnieją setki dostępnych wzorców, niemożliwe jest więc omówienie wszystkich, dlatego w niniejszym rozdziale wybrano kilka najbardziej popularnych, a także kilka najbardziej użytecznych. Jeśli Czytelnik nie znajdzie tutaj tego, czego szuka, warto zajrzeć na wspomnianą wcześniej stronę internetową i poszukać danego wzorca, gdyż można ich tam znaleźć pokaźną liczbę. Ponieważ wzorce są stosunkowo proste, w niniejszym rozdziale niewiele miejsca zajmie omówienie ich; bardziej wartościowy będzie sam kod. Pierwszym problemem jest sprawdzanie poprawności formularzy. 1
Na bazie wzorców gromadzonych na stronie Michael Mahemoff napisał również książkę Ajax Design Patterns (O’Reilly, 2006), dostępną w Polsce pod tytułem Ajax. Wzorce projektowe (Helion, 2007) — przyp. tłum.
Rozdział 9.
Wzorce
317
Sprawdzanie poprawności formularzy Sprawdzanie poprawności formularzy nie jest ulubionym zajęciem wielu programistów. Jest jednak niezbędne, jeśli chce się odfiltrować wiele przypadkowych informacji bądź spamu, jaki użytkownicy wpisują do formularzy.
Problem Czekanie na to, aż użytkownik wpisze całą stronę danych, zanim spróbuje się te dane sprawdzić, jest wąskim gardłem wielu aplikacji, z którym programiści próbują sobie poradzić od lat. Jeśli sprawdza się poprawność jedynie po stronie klienta, nie ma się dostępu do bazy danych w celu otrzymania szczegółowych informacji. Jeśli sprawdzanie poprawności danych w całości odbywa się po stronie serwera, czas reakcji nie jest zbyt szybki. Często zdarza się zatem, że programiści sprawdzają poprawność danych zarówno po stronie klienta, jak i po stronie serwera.
Wzorzec Istnieją dwa warianty wzorców, które można wykorzystywać w sprawdzaniu poprawności formularzy:
Należy przesłać każde pole, kiedy jego wartość się zmienia bądź też kiedy pole to przestaje być aktywne.
Należy co jakiś czas przesyłać zawartość formularza w celu sprawdzenia jej poprawności.
Wybór jednego z powyższych rozwiązań tak naprawdę zależy od konkretnej sytuacji. Należy pamiętać, że sprawdzanie poprawności formularzy jest obszarem, w którym trzeba bardzo uważać. Jeśli ktoś próbuje sprawdzać poprawność po każdym naciśnięciu klawisza, aż prosi się o kłopoty, gdyż będzie to niezgodne z chęcią stworzenia wygodnego i bogatego środowiska dla użytkownika. Pierwszy scenariusz rozpocznie się od utworzenia przykładu, w którym użytkownik zostanie zapytany o kilka informacji, a wśród nich będzie identyfikator użytkownika. Jak wspomniano w rozdziale 1., techniki Ajaksa mogą być bardzo natrętne, dlatego w niniejszym przykładzie celowo nie są one wykorzystane do sprawdzenia każdego szczegółu formularza. Pod uwagę wzięty zostanie identyfikator użytkownika (UserName), a kiedy pole to przestanie być aktywne (o czym wiadomo dzięki uruchomieniu zdarzenia onblur), jego zawartość zostanie przesłana do serwera, który z kolei wykona zapytanie do bazy danych Access2 zawierającej listę identyfikatorów. Następnie kod wyświetli użytkownikowi komunikat, informując go o tym, czy wybrany identyfikator jest jeszcze dostępny.
2
Plik chapter9.mdb z bazą danych znajduje się w kodach do pobrania ze strony książki — przyp. tłum.
318
Ajax. Od podstaw Przykład ten zmieni tekst formularza w zależności od tego, czy użytkownik wybierze opcję PL, czy US w country. Nie jest to wykonywane za pomocą Ajaksa, a dzięki dynamicznemu JavaScriptowi. W ten sposób widać, że należy wykorzystywać Ajaksa tylko tam, gdzie jest on naprawdę potrzebny.
spróbuj sam Przesyłanie wartości, kiedy pole przestaje być aktywne By wypróbować przesyłanie wartości, kiedy pole formularza przestaje być aktywne, należy wykonać następujące kroki: 1.
Należy utworzyć stronę HTML o nazwie FormValidation.htm o następującej zawartości:
Przykład sprawdzania poprawności formularzy
Preferowany identyfikator użytkownika:
Imię:
Nazwisko:
Adres:
Miasto:
Państwo: PL US
Województwo/stan:
Kod pocztowy:
Rozdział 9.
Wzorce
2. Należy utworzyć skrypt o nazwie FormValidation.js o następującej zawartości: var xHRObject = false; if (window.XMLHttpRequest) { xHRObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); } var NameTaken = "False"; function getData() { if ((xHRObject.readyState == 4) && (xHRObject.status == 200)) { var serverText = xHRObject.responseText; if (serverText == "True") { span.innerHTML = "Ten identyfikator użytkownika jest już zajęty."; NameTaken = "True"; } if (serverText == "False") { span.innerHTML = "Ten identyfikator użytkownika jest dostępny."; NameTaken = "False"; } } } function getBody(newform, data) { var argument = data + "="; argument += encodeURIComponent(document.getElementById(data).value) return argument; } function Validate(data) { var newform = document.forms[0]; var bodyofform = getBody(newform, data); if (bodyofform != "UserName=") { xHRObject.open("POST", "Validate.php", true); xHRObject.setRequestHeader("Content-Type", "application/ x-www-form-urlencoded"); xHRObject.onreadystatechange = getData; xHRObject.send(bodyofform); ; } else { span.innerHTML = "Identyfikator użytkownika nie może być pusty."; } }
319
320
Ajax. Od podstaw
function Submit(data) { if (NameTaken == "False") { var newform = document.forms[0]; var bodyofform = getBody(newform, data); if (bodyofform != "UserName=") { window.location = "FormCheck.php"; } else { span.innerHTML = "Identyfikator użytkownika nie może być pusty."; } } } function Change() { if(state.innerHTML == "Województwo/stan:") { state.innerHTML = "Stan:" zipcode.innerHTML = "Kod pocztowy:" } else { state.innerHTML = "Województwo:" zipcode.innerHTML = "Kod pocztowy:" } }
3. Należy utworzyć stronę w ASP.NET o nazwie Validate.aspx o następującej
zawartości:
Można również utworzyć następujący skrypt w PHP:
4. Należy utworzyć niewielki arkusz stylów o nazwie FormValidation.css: .textbox { position: absolute; left: 150px; } span#span { color: red; }
5. Na koniec należy dodać krótką fikcyjną stronę, by zapewnić, że program nie zwróci
błędu, kiedy kliknie się Kliknij tutaj w celu przesłania informacji. Strona ta powinna nosić nazwę FormCheck.aspx.
321
322
Ajax. Od podstaw
W PHP należy zastosować poniższy kod z pliku FormCheck.php:
6. Należy otworzyć stronę FormValidation.htm w przeglądarce, wpisać identyfikator użytkownika Aleksander (jak na rysunku 9.1), a następnie przejść do kolejnego pola.
Nie należy przesyłać formularza (klikać przycisku na dole strony)!
Rysunek 9.1. Podanie danych na stronie FormValidation.htm
Jak to działa Powyższy przykład powinien wyglądać dość znajomo. Do przesyłania danych wykorzystano metodę POST. Pole tekstowe dla UserName zawiera wywołanie funkcji Validate z JavaScriptu. Jest ona wywoływana dopiero wtedy, gdy uruchomione zostanie zdarzenie onblur. Zdarzenie to jest przeciwieństwem onfocus, zatem wywołane zostanie dopiero wtedy, gdy użytkownik przejdzie do kontrolki, która staje się aktywna, a następnie przejdzie dalej, tak by kontrolka stała się nieaktywna. onblur="Validate('UserName')"
Rozdział 9.
Wzorce
323
W JavaScripcie inicjalizuje się obiekt XMLHttpRequest poza wszystkimi funkcjami, dzięki czemu staje się on globalnie dostępny: var xHRObject = false; if (window.XMLHttpRequest) { xHRObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); }
Następnie w funkcji Validate przekazuje się nazwę kontrolki do kodu po stronie serwera. Wykorzystano metodę POST (jak zazwyczaj robi się to w przypadku formularzy) i funkcję getBody do zakodowania danych w postaci URI. function Validate(data) { var newform = document.forms[0]; var bodyofform = getBody(newform, data); if (bodyofform != "UserName=") { xHRObject.open("POST", "Validate.php", true); xHRObject.setRequestHeader("Content-Type", "application/x-www-formurlencoded"); xHRObject.onreadystatechange = getData; xHRObject.send(bodyofform); ; } else { span.innerHTML = "Identyfikator użytkownika nie może być pusty."; } }
Można również sprawdzić, czy użytkownik podał pusty identyfikator, ponieważ w takiej sytuacji nie ma sensu sprawdzać zawartości formularza. Jeśli użytkownik podał jakiś identyfikator, można przesłać zawartość tych danych do pliku FormCheck.aspx bądź FormCheck.php, w zależności od tego, której technologii po stronie serwera się używa. Kod po stronie serwera tworzy zmienną check typu Boolean wskazującą na to, czy identyfikator użytkownika został dopasowany. Na początku zakłada się, że nie został on dopasowany. Następnie tworzy się połączenie z bazą danych Access i otwiera się ją za pomocą Open: bool check = false; OleDbConnection SourceDb = new OleDbConnection("PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath("chapter9.mdb") + ";"); SourceDb.Open();
Tworzy się instrukcję SQL, która wybiera całą zawartość tabeli Users. Jeśli otworzy się tabelę Users, zobaczy się, że zawiera ona jedynie dwie kolumny. Pierwsza kolumna zawiera unikalny identyfikator, natomiast druga — zbiór identyfikatorów użytkowników. Można wykonać to zapytanie SQL na bazie danych. Wykonuje się iterację po każdym wierszu tabeli Users, sprawdzając, czy identyfikator podany w polu formularza odpowiada identyfikatorowi
324
Ajax. Od podstaw podanemu przez użytkownika. Dopiero kiedy tak się stanie, wartość zmiennej check typu Boolean zostanie zmieniona na true. OleDbCommand myOleDbCommand = new OleDbCommand("SELECT * from Users;", SourceDb); OleDbDataReader oleDbReader = myOleDbCommand.ExecuteReader(); while (oleDbReader.Read()) { if (Request.Form["UserName"] != null) { if (Request.Form["UserName"] == oleDbReader["UserName"].ToString()) { check = true; } } }
Na koniec zamyka się oraz czyści połączenie. Zawartość zmiennej check zapisuje się do strumienia Response. SourceDb.Close(); SourceDb.Dispose(); Response.Write(check);
Funkcja getData obsługuje odpowiedź z serwera. Powracająca odpowiedź będzie zawierała albo True, albo False (choć, jak okaże się w dalszej części rozdziału, możliwy jest również trzeci scenariusz, który należy wziąć pod uwagę). Jeśli odpowiedź zawiera słowo true, natychmiast wskazuje na to, że użytkownik wybrał niedostępny już identyfikator — zanim prześle on formularz. W innym przypadku można użytkownika poinformować o tym, że jego identyfikator jest w porządku. var NameTaken = "False"; function getData() { if ((xHRObject.readyState == 4) && (xHRObject.status == 200)) { var serverText = xHRObject.responseText; if (serverText == "True") { span.innerHTML = "Ten identyfikator użytkownika jest już zajęty."; NameTaken = "True"; } if (serverText == "False") { span.innerHTML = "Ten identyfikator użytkownika jest dostępny."; NameTaken = "False"; } } }
Zmienna globalna NameTaken ustawiona jest tak, by utworzyć „pamięć” tego, czy identyfikator jest dostępny, na wypadek gdyby okazało się, że dalsze uaktualnienia strony spowodowały, iż odpowiedzi z właściwości responseText nie są ani true, ani false.
Rozdział 9.
Wzorce
325
Przysłanie formularza obsługiwane jest przez osobny kod po stronie serwera, który może wykonywać odrębne sprawdzanie poprawności danych. Jak wspomniano wcześniej, pewne typy informacji lepiej jest sprawdzać w czasie wpisywania przez użytkownika, natomiast na inne lepiej jest poczekać, aż użytkownik prześle formularz. Ostatnią niewielką częścią jest funkcja Change, która nie jest ściśle oparta na Ajaksie, ale dobrze uzupełnia sprawdzanie UserName. W przykładzie tym informację o państwie celowo umieszczono ponad informacjami o województwie (stanie) oraz kodzie pocztowym; kiedy zatem użytkownik wybierze państwo z listy rozwijanej, podpisy dwóch kolejnych pól tekstowych zostaną automatycznie zastąpione odpowiednimi. function Change() { if(state.innerHTML == "Województwo/stan:") { state.innerHTML = "Stan:" zipcode.innerHTML = "Kod pocztowy:" } else { state.innerHTML = "Województwo:" zipcode.innerHTML = "Kod pocztowy:" } }
Funkcja Change zmienia po prostu właściwość innerHTML odpowiedniego znacznika span w zależności od tego, czy jest ona ustawiona na stan, czy na województwo.
Dodatkowe informacje we wzorcach związanych z najeżdżaniem myszą na element Najeżdżanie myszą na element (ang. mouseover) to popularne rozwiązanie służące do dynamicznego pokazywania informacji na stronach internetowych przez dłuższy czas. Choć techniki dynamicznego HTML oznaczają, że można przebudować stronę, tak by wyświetlane były dodatkowe informacje, pomysł przesuwania informacji tam i z powrotem, by dynamicznie odpowiadały one nowym częściom strony, może być dość niezgrabny. Technika z najeżdżaniem myszą na element pozwala na uniknięcie tych problemów, nie wpływając jednocześnie na układ oryginalnych informacji na ekranie.
Problem W jaki sposób można pokazać dodatkowe informacje o elemencie bez wprowadzania nieładu do jego prezentacji bądź też bez odrywania użytkownika od jego aktualnych działań?
326
Ajax. Od podstaw
Wzorzec Częściowo przezroczysta wyskakująca ramka pozwala na wyświetlanie dodatkowych informacji na temat określonego elementu. Nie zakłóca to układu strony, a częściowa przezroczystość oznacza, że oryginalne informacje na stronie nie zostaną całkowicie przysłonięte. Często zdarza się, że na stronach internetowych wyświetlana jest lista grafik (na przykład zdjęć zespołów muzycznych z Last.fm czy też grupy fotografii z Flickr). Powiedzenie, że jedno zdjęcie jest warte tyle, ile tysiąc słów, wydaje się dość popularne we współczesnym projektowaniu stron internetowych. Mając zatem wiele produktów w swoim katalogu, można wyświetlić je jako serię zdjęć. W takie sytuacji wykorzystywane są wyskakujące ramki, ponieważ są one szybkie w użyciu i nie zmieniają układu samej strony, dzięki czemu są bardzo popularne. Poniższy przykład wyświetla okładki sześciu książek. Kiedy użytkownik najedzie myszą na okładkę, otrzyma większą jej wersję wraz ze szczegółowymi informacjami na temat książki. W przykładzie tym wykorzystano istniejącą bibliotekę boxover.js, dostępną na stronie http://boxover.swazz.org, która jest bardzo popularna i sama zajmuje się wyświetlaniem obrazków. Ściśle mówiąc, nie wymaga ona Ajaksa, jednak w przykładzie Ajax wykorzystany zostanie do przejścia do pliku XML, zidentyfikowania wybranej książki po numerze ISBN, a następnie zwrócenia niewielkiej ilości informacji na temat książki (na przykład tytułu, autora, numeru ISBN oraz ceny). Informacje te zostaną następnie wyświetlone w wyskakującej ramce.
spróbuj sam Wyświetlanie przezroczystej wyskakującej ramki By wypróbować wyświetlanie przezroczystej ramki w praktyce, należy postępować zgodnie z poniższymi krokami: 1.
Należy utworzyć stronę o nazwie MouseOver.htm o następującej treści:
Przykład z najechaniem myszą na element
2. Należy pobrać najnowszą wersję biblioteki boxover.js ze strony
http://boxover.swazz.org i umieścić ją w tym samym folderze. 3. Należy odnaleźć funkcję getParam i zmienić ją w następujący sposób,
dodając zaznaczony kod: function getParam(param,list) { var reg = new RegExp('([^a-zA-Z]' + param + '|^' + param + ')\\s*=\\s*\\[\\s*(((\\[\\[)|(\\]\\])|([^\\]\\[]))*)\\s*\\]'); var res = reg.exec(list); var returnvar; if(param != "body") { if(res) return res[2].replace('[[','[').replace(']]',']'); else return ''; } else { if (res) return mousebox(res[2].replace('[[','[').replace(']]',']')); else return ''; } }
4. Należy utworzyć nowy skrypt o nazwie mouse.js i dodać do niego następujący
kod: var isbn = null; var http = null; function mousebox(isbn) { if (window.ActiveXObject) { http = new ActiveXObject("Microsoft.XMLHTTP"); } else if (window.XMLHttpRequest) {
327
328
Ajax. Od podstaw http = new XMLHttpRequest(); } http.open("GET", "Catalogue.xml", false); http.send(null); var xml = http.responseXML; // Załadowanie XSL if (window.ActiveXObject) { var xsl = new ActiveXObject("MSXML2.FreeThreadedDomDocument.3.0"); xsl.async = false; xsl.load("Catalogue.xsl"); var template = new ActiveXObject("MSXML2.XSLTemplate"); template.stylesheet = xsl; processor = template.createProcessor(); processor.input = xml; processor.addParameter("ISBN", isbn); processor.transform(); // Transformacja return processor.output; } else { var xsltProcessor = new XSLTProcessor(); // Załadowanie XSL http = new XMLHttpRequest(); http.open("GET", "Catalogue.xsl", false); http.send(null); xslStylesheet = http.responseXML; xsltProcessor.importStylesheet(xslStylesheet); xsltProcessor.setParameter(null, "ISBN", isbn); // Transformacja var fragment = xsltProcessor.transformToFragment(xml, document); return new XMLSerializer().serializeToString(fragment); } }
5. Należy utworzyć plik o nazwie Catalogue.xml z następującymi danymi:
Ajax. Zaawansowane programowanie Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett 978-83-246-0567-5 67.00
ActionScript 2.0. Od podstaw Nathan Derksen, Jeff Berg 978-83-246-0655-9
Rozdział 9.
Wzorce
99.00
CSS. Gotowe rozwiązania Richard York 83-246-0574-6 49.00
JavaScript dla webmasterów. Zaawansowane programowanie Nicholas C. Zakas 83-246-0280-1 89.00
.NET Framework 2.0. Zaawansowane programowanie Joe Duffy 978-83-246-0654-2 89.00
SQL Server 2005. Programowanie. Od podstaw Robert Vieira 83-246-0653-X 97.00
6. Należy utworzyć nowy plik o nazwie Catalogue.xsl i wstawić do niego
poniższy kod:
Tytuł
Autor
ISBN
329
330
Ajax. Od podstaw
Cena
7. Należy otworzyć stronę MouseOver.htm w przeglądarce, najechać myszą na każdą
z okładek książki po kolei, jak na rysunku 9.2.
Rysunek 9.2. Najechanie myszą na okładkę książki
Jak to działa Niniejszy przykład korzysta z dość rozbudowanej istniejącej biblioteki i w niewielkim stopniu poprawia ją, by można było wykorzystać Ajaksa do pobrania informacji oraz wyświetlenia ich na stronie. Nie ma co wchodzić w szczegóły działania biblioteki boxover.js, ponieważ wykonuje ona dość skomplikowane operacje mające na celu zapewnienie, że ramka podąża za myszą, kiedy pojawia się i znika przy przechodzeniu do kolejnych elementów. Strona HTML zawiera pierwszą interesującą nas kwestię. Każda okładka zawiera pewne dodatkowe informacje przekazane w atrybucie title.
Rozdział 9.
Wzorce
331
0"> | Produkt | ISBN | Ilość | Cena | |
Dodatek A
Rozwiązania ćwiczeń
| | | PLN | |
|
Suma: | PLN | |
Twój koszyk jest pusty |
|
455
456
Ajax. Od podstaw
Rozdział 9. Ćwiczenie 1. Należy zmienić przykład ze sprawdzaniem poprawności formularza w taki sposób, by nie było możliwe przesyłanie formularza, kiedy identyfikator UserName wybrany przez użytkownika jest już zajęty.
Rozwiązanie Należy wprowadzić następujące zmiany do pliku FormValidation.htm:
Przykład sprawdzania poprawności formularzy
Preferowany identyfikator użytkownika:
Imię:
Nazwisko:
Adres:
Miasto:
Państwo: PL US
Województwo/stan: Kod pocztowy: Należy do skryptu FormValidation.js dodać zmienną globalną NameTaken: var NameTaken = "False";
Dodatek A
Rozwiązania ćwiczeń
457
Trzeba również zmodyfikować kod funkcji getData w następujący sposób: function getData() { if ((xHRObject.readyState == 4) && (xHRObject.status == 200)) { var serverText = xHRObject.responseText; if (serverText == "True") { span.innerHTML = "Ten identyfikator użytkownika jest już zajęty."; NameTaken = "True"; } if (serverText == "False") { span.innerHTML = "Ten identyfikator użytkownika jest dostępny."; NameTaken = "False"; } } }
Należy również dodać do skryptu FormValidation.js nową funkcję submit: function submit(data) { if (NameTaken == "False") { var newform = document.forms[0]; var bodyofform = getBody(newform, data); if (bodyofform != "UserName=") { window.location = "FormCheck.php"; } else { span.innerHTML = "Identyfikator użytkownika nie może być pusty."; } } }
Ćwiczenie 2. Należy zmodyfikować ostatni przykład z ponawianiem żądania w taki sposób, by zamiast wyświetlać komunikat, odliczał do dziesięciu i przestawał wyświetlać jakiekolwiek informacje o notowaniach. Następnie powinien on wyświetlić nowy komunikat powiadamiający użytkownika, że informacje nie są obecnie dostępne.
Rozwiązanie Należy dodać następującą zmienną globalną: var Count = 0;
Należy zmodyfikować funkcję getData() w następujący sposób: function getData() { // Sprawdzenie czy obiekt XMlHttpRequest jest gotowy oraz czy zwrócił poprawną odpowiedź
458
Ajax. Od podstaw
}
if (xHRObject.readyState == 4) { if (xHRObject.status == 200) { // Załadowanie XML var xml = loadDocument("Stocks.xml"); // Załadowanie XSL var xsl = loadDocument("Stocks.xsl"); // Transformacja document.getElementById("Stocks").innerHTML = transformToHTML(xml, xsl); // Wyczyszczenie obiektu i wywołanie funkcji getDocument za pięć sekund setTimeout("getDocument()", 5000); } else { var Stocks = document.getElementById("Stocks"); if (Stocks.innerHTML.indexOf("dostępne")==-1) { Count++; } if (Count>=10) { Stocks.innerHTML = "
Aktualne notowania akcji nie są dostępne"; } xHRObject.abort(); setTimeout("getDocument()", 5000); } }
Rozdział 10. Rozdział ten skupia się na wykorzystywaniu Ajaksa do pobierania danych zewnętrznych z plików kanałów informacyjnych XML, a także na ekstrakcji danych, ich przetwarzaniu oraz wyświetlaniu na stronach internetowych.
Ćwiczenie 1. Należy dodać do strony ch10_examp1.htm kod w JavaScripcie, który przekonwertuje odnośnik tekstowy na prawdziwy odnośnik, kiedy dane wyświetlane są na stronie. var link = item.getElementsByTagName('link')[0].firstChild.data; document.getElementById('link').innerHTML = link;
Rozwiązanie var link = item.getElementsByTagName('link')[0].firstChild.data; var link2 = "" + link + ""; document.getElementById('link2').innerHTML = link2; ... Odnośnik:
Dodatek A
Rozwiązania ćwiczeń
459
Należy wykorzystać JavaScript do dodania kodu HTML do zmiennej link. Należy utworzyć nową zmienną o nazwie link2, a następnie dodać początek znacznika otwierającego a wraz z atrybutem href. Kod HTML traktowany jest jak łańcuch znaków, dlatego musi być umieszczony w cudzysłowie. Apostrof po znaku = zostanie wykorzystany jako wartość URL. Konieczne będzie zastosowanie tutaj apostrofu w celu odróżnienia go od cudzysłowu kończącego łańcuch znaków. W przeciwnym razie drugi cudzysłów zostałby błędnie zinterpretowany jako koniec łańcucha znaków. "