Mootools 1.1 - Ajax.js

08 lipca, 2007

Plik ajax.js zawiera klasę Ajax, która jest rozszerzeniem poznanej w poprzedniej części kursu klasy XHR. Klasa Ajax zawiera 4 metody i posiada dodatkowe zdarzenie... Poza tym mamy do dyspozycji wszystkie metody, opcje i zdarzenia klasy XHR.

Stworzenie nowego obiektu tej klasy wygląda następująco:

obiekt = new Ajax(adres,opcje);

Gdzie zmienna adres to najczęściej adres pod którym znajduje się skrypt przetwarzający otrzymane dane. Zmienna opcje to tak naprawdę cały obiekt, przechowujący parametry wywołania obiektu klasy Ajax. Oprócz opcji znanych z klasy XHR mamy jeszcze do dyspozycji 4 dodatkowe opcje:

  • data - opcja ta przechowuje dane jakie chcemy wysłać zapytaniem Ajax. Może być zarówno ciągiem znaków urlescape jak i obiektem gdzie rolę pól pełnią nazwy zmiennych. Trzecią możliwością jest umieszczenie w tym miejscu odwołania do elementu formularza.
  • update - w tej opcji określamy element w którym pojawią się pobrane przez zapytanie dane.
  • evalScripts - jeżeli pobieramy za pomocą zapytania kod JavaScript to po jego pobraniu możemy go wykonać wtedy gdy opcja ta ustawiona jest jako true. Domyślna wartość tej opcji to false.
  • evalResponse - ta opcja ma podobne działanie do poprzedniej z tą różnicą, że wykonuje skrypty JS niezależnie od tego jakiego typu są pobierane dane... Domyślna wartość tej opcji to false.

Jak już wspominałem klasa Ajax udostępnia nam jedno dodatkowe zdarzenie - onComplete, które jest wywoływane w momencie zakończenia wykonywania zapytania. Jaka jest różnica pomiędzy zdarzeniem onComplete, zdarzeniem onSuccess znanym z klasy XHR ? Opcje takie jak update czy evalScripts i evalResponse zadziałają tylko w momencie wywoływania zdarzenia onComplete - stosując zdarzenie onSuccess stosowanie tych opcji mija się z celem.

Przejdźmy teraz do tego co nas najbardziej interesuje - do metod udostępnianych przez klasę Ajax.

Request

Metoda request to podstawa działania klasy Ajax - służy do wysłania zapytania zgodnie z podanymi parametrami.

Metodę tę możemy wywoływać na dwa sposoby:

obiekt = new Ajax(adres,opcje);
obiekt.request();

lub:

new Ajax(adres,opcje).request();

Pierwszy sposób jest lepszy gdy chcemy wykonywać dane zapytanie wielokrotnie, a drugie rozwiązanie jest przydatne w wypadku pojedynczych wywołań.

Wykonajmy zatem zapytanie Ajax, które pobierze tekst z danej strony i umieści go w odpowiednim elemencie. Żeby było ciekawiej to będziemy mogli pobrany tekst umieścić w wybranym przez nas elemencie. Ponieważ będziemy wykonywać kilka zapytań warto skorzystać z pierwszego sposobu zapisu by nie tworzyć kilku-kilkunastu instancji klasy Ajax - będziemy po prostu dynamicznie zmieniać wartość jednej z opcji naszego obiektu.

Ponieważ wszystko będzie najlepiej widoczne w przykładzie tu skupię się tylko na samym schemacie działania skryptu.

Stworzymy listę wyboru typu select, która pozwoli nam na wybór elementu w którym znajdzie się pobrany przez zapytanie tekst. Zapytanie zostanie wykonane w momencie kliknięcia przycisku. Zatem w tym momencie musimy zmienić wartość opcji update obiektu klasy Ajax (który utworzymy wraz ze zdarzeniem onload obiektu window).

Tworzymy obiekt klasy Ajax przy zdarzeniu onload :

window.addEvent("load",function(){
   zapytanie = new Ajax('http://adres.pl');
});

Dodajemy zdarzenie onclick do przycisku, które pobiera wartość pola select i na tej podstawie zmienia opcję update obiektu klasy Ajax i wykonuje zapytanie:

window.addEvent("load",function(){
   zapytanie = new Ajax('http://adres.pl');

   $('btn').addEvent("click",function(){
      zapytanie.options.update = $($('select').value);
      zapytanie.request();
   });
});

Powyższy kod w akcji prezentuję w poniższym przykładzie:

PRZYKŁAD 1

evalScripts

Metoda evalScripts służy do wykonywania skryptów zawartych w zwróconym przez zapytanie tekście, zgodnie z podanymi opcjami. Metody tej z reguły nie stosujemy ręcznie, ponieważ jest ona automatycznie wywoływana w momencie zaistnienia zdarzenia onComplete, gdy opcja evalResponse lub evalScripts ma wartość true.

Oczywiście można użyć tej metody ręcznie w momencie, gdy chcemy wykonać kody JS zawarte w wyniku zapytania w innym momencie działania naszego skryptu - czyli niekoniecznie zaraz po zakończeniu wykonania zapytania.

Przykładowo pobraliśmy kod skryptu i chcemy go wykonać na przykład w momencie kliknięcia jakiegoś elementu. Jeżeli pobraliśmy tylko kod skryptu to nie musimy zmieniać wartości opcji obiektu klasy Ajax - gdy chcemy skorzystać z właściwości opcji evalResponse to przed wywołaniem tej metody musimy zmienić wartość tej opcji na true (gdyby miała ona taką wartość od momentu inicjalizacji obiektu to nie moglibyśmy wykonać skryptu w dowolnym momencie, gdyż wykonałby się on wraz ze zdarzeniem onComplete obiektu).

Tworzymy zatem nowy obiekt klasy Ajax przy zdarzeniu onload:

window.addEvent("load",function(){
   zapytanie = new Ajax('http://adres.pl');
});

Tworzymy też dwa przyciski - btn1 i btn2 z których pierwszy będzie wykonywał zapytanie, a drugi wykona zawarty w zapytaniu kod JS.

Zatem:

window.addEvent("load",function(){
   zapytanie = new Ajax('http://adres.pl');

   $('btn1').addEvent("click",function(){
      zapytanie.request();
   });

   $('btn2').addEvent("click",function(){
      zapytanie.evalScripts();
   });
});

Jeszcze by się przydało dać jakiś sygnał, że zapytanie się wykonało - dodajemy do obiektu klasy Ajax zdarzenie onComplete:

window.addEvent("load",function(){
   zapytanie = new Ajax('http://adres.pl',{onComplete: function(){alert('zapytanie zakończone...')}});

   $('btn1').addEvent("click",function(){
      zapytanie.request();
   });

   $('btn2').addEvent("click",function(){
      zapytanie.evalScripts();
   });
});

Oczywiście powyższy kod dotyczy sytuacji gdzie pobieramy czysty kod JS - z odpowiednim Content-Type lub kod zawarty pomiędzy znacznikami script:

PRZYKŁAD 2

To teraz wersja dla pobierania kodu JS ale bez Content-Type - to samo tylko z drobnymi modyfikacjami:

window.addEvent("load",function(){
   zapytanie = new Ajax('http://adres.pl',{onComplete: function(){alert('zapytanie zakończone...')}});

   $('btn1').addEvent("click",function(){
      zapytanie.request();
   });

   $('btn2').addEvent("click",function(){
      zapytanie.options.evalResponse = true;
      zapytanie.evalScripts();
   });
});

Jak widać zmieniła się tylko jedna linijka kodu w funkcji wykonywanej przy zdarzeniu onclick dla drugiego przycisku.

I oczywiście kod w działaniu:

PRZYKŁAD 3

getHeader

Metoda getHader służy do pobierania zawartości danego nagłówka odpowiedzi. Jako jej argument podajemy nazwę nagłówka - w wypadku gdy takowy nagłówek nie istnieje zwrócona zostaje wartość null.

Składnia tej metody wygląda następująco :

obiekt_ajax.getHeader('nazwa_naglowka');

Przykładowo gdybyśmy chcieli pobrać nagłówek Content-Type to zapiszemy:

obiekt_ajax.getHeader('Content-Type');

No i musimy pamiętać by umieścić kod pobierający zawartość nagłówka tak by wykonał się po wykonaniu zapytania - na przykład w zdarzeniu onComplete.

Przykład używający tej metody poniżej:

PRZYKŁAD 4

Object.toQueryString

Funkcja Object.toQueryString zamienia podany jako argument obiekt na ciąg znaków urlescape. Składnia tej funkcji:

Object.toQueryString(obiekt);

Na przykład:

Object.toQueryString({imie: "Tomek",nick: "Dziudek", www: "dziudek.jogger.pl"});

Powyższy kod zamieni podany obiekt na następujący ciąg znaków:

imie=Tomek&nick=Dziudek&www=dziudek.jogger.pl

Myślę, że przykład działania niepotrzebny bo podobne funkcje już poznawaliśmy i powinniście już wiedzieć kiedy ta funkcja się przyda ;)

send

Ostatnia metoda w pliku ajax.js - jest rozszerzeniem klasy Element, a co za tym idzie możemy ją łączyć z wybranym elementem - w tym wypadku formularzem. Jej działanie polega na wysyłaniu za pomocą Ajax danego formularza. Składnia funkcji:

$('formularz').send(opcje);

Opcje to w tym wypadku opcje klas Ajax i XHR - oczywiście poza parametrami typu adres czy dane, które są generowane automatycznie na podstawie zawartości formularza.

Przykładowo zapis:

$('form').send();

Spowoduje wysłanie formularza posiadającego identyfikator "form" pod adres zgodny z atrybutem action elementu form i z danymi automatycznie zamienionymi na format urlescape. Warto jeszcze dodać, że dane w tym wypadku są wysyłane metodą post.

I przykład korzystający z tej metody:

PRZYKŁAD 5

Może jest mało ciekawy, ale ma po prostu pokazać jak to mniej więcej działa ;]

To by było na tyle w temacie pliku ajax.js . W następnej części kursu zajmę się plikiem assets.js, który pozwala na dynamiczne dołączanie skryptów, styli i grafik do stron.

Komentarze do wpisu "Mootools 1.1 - Ajax.js":

1. ewel napisał(a):
04 września 2007, 16:32:29

po pierwsze to dzieki za bardzo fajny kursik, jestem tu ostatnio prawie codziennie ;)

po drugie, mam pytanie takie: czy takiej sytuacji:

********
window.addEvent(‘domready’, function(){ $(‘myForm’).onsubmit= function(e) { new Event(e).stop(); this.send({ onComplete: function(){( new Element(‘span’).appendText(this.response.text).injectAfter($(‘login’)) )} }); };
}); ******
jest mozliwe w ogole otrzymanie odpowiedzi w formacie xml?

chodzi mi o sytuacje gdy po stronie serwera mamy obsluge bledow i w zaleznosci od tego, ktory blad wywala w odpowiednim miejscu przy formularzu pojawia sie odpowiedz z serwera. jesli odbieram odpowiedz w formacie text wszytko dziala jak nalezy (oczywiscie uaktualnione zostaje tylko jedno pole, z roznymi komunikatami o bledach, tak jakbym uzywala ‘update’), ale jak tylko wrzucam tam format xml, po stronie serwera tworze plik xml i odwoluje sie do jego poszczegolnych pol przez getElementsByTagName(pole).firstChild.data dostaje komunikaty ‘this.response.xml has no properties’

mozna to jakos obejsc?

2. Dziudek napisał(a):
04 września 2007, 16:38:50

ewel – na pierwszy rzut oka brakuje mi po kodzie:
getElementsByTagName(pole) (swoją drogą jak pole jest ciągiem znaków, a nie zmienną to powinno być getElementsByTagName("pole")) właściwości:
.item(0) – metoda getElementsByTagName zwraca kolekcję elementów, a nie jeden element i dopiero po tym .item(0) odwołujemy się do firstChild itd. ;) Czyli kod powinien wyglądać następująco:

getElementsByTagName('nazwa_tagu').item(0).firstChild.data

3. ewel napisał(a):
04 września 2007, 21:04:37

zmienilam, ale caly czas daje: ‘this.response.xml has no properties’....
zastanawiam sie czy zle nie tworze xml po stronie serwera, bo robie to pierwszy raz. czy wystarczy wypluc echo z deklaracja xml oraz echo z poszczegolnymi tagami?

4. Dziudek napisał(a):
04 września 2007, 21:19:21

@ewel – IMHO na początku kodu PHP powinno być:

header("Content-type: text/xml; charset=UTF-8"); echo '<?xml version="1.0" encoding="UTF-8"?>';

5. ewel napisał(a):
04 września 2007, 21:35:53

caly czas to samo, ten sam komunikat o bledzie…
kod php do ktorego wysylam formularz mam w osobnym pliku, moze musi byc w tym samym? bo gdy wylacze javascript daje mi komunikat ze naglowki zostaly wyslane (nie, nie mam zadnych zbednych linii ani znakow w kodzie ;))

6. Dziudek napisał(a):
04 września 2007, 21:41:39

@ewel – możesz wrzucić ten przykład na jakąś stronkę albo wysłać mi na mail ? Tak chyba będzie szybciej ;)

7. Visa napisał(a):
11 września 2007, 21:23:52

Object.toQueryString tak to se mozna wysylac argumenty getem postem ;) zarty a jak jest w nazwie jakiegos pola & ? to co dżijaidżo ? new Ajax( ‘index.php?a=1&b=2’ ) to rozwiazanie dla nobów i prostych rzeczy nigdy nie wystarczy

Get JSON or Die trying ;)

8. Dziudek napisał(a):
11 września 2007, 21:28:51

@Visa – JSON to swoją drogą – ja opisywałem wszystkie możliwości MooTools, a nie tylko te, które mi się podobają :)

9. jimmy0699 napisał(a):
12 kwietnia 2008, 14:53:59

hej, na poczatek powiem ze kurs jest naprawde super i wydrukowalem sobie caly (92 kartki ;]).
mam pewien problem i bylbym wdzieczny gdybys wskazal wlasciwa droge…
while ($q=$sql->fetchArray()) { $ext1.="<a class=menu href=#>{$q['name']}</a>"; $myJava.=" var menu_ajax = $$('.menu'); menu_ajax.addEvent('click', function(e) { new Event(e).stop(); var log = $('content').empty().addClass('ajax-loading'); new Ajax(\"http://localhost/~cms/\", { method: 'get', update: $('content'), data: 'x='+".$q['id'].", onComplete: function() { log.removeClass('ajax-loading'); } }).request(); }); "; }
a pytanie to: jak wyselekcjonowac zapytania…

10. Dziudek napisał(a):
12 kwietnia 2008, 15:05:28

@jimmy0699 – chyba nie bardzo zrozumiałem pytanie ;) Nie wiem, może jestem zbyt zmęczony ostatnio, ale jakbyś mógł to opisz dokładniej o co chodzi :)

11. jimmy0699 napisał(a):
12 kwietnia 2008, 15:12:48

mam na stronie glowne menu ;], jest ono pobierane z mysqla, i wyswietlane za pomoca while ($q=$sql->fetchArray()) {...}
w srodku jest robione menu w jakis tam sposob typu
$menu.="<a href=#></a>" oraz kod js ktory pobierze opowiednie dane metoda Ajax wedlug zmiennej $q['id']. nie jestem zbytnio obyty z js i problem polega na tym ze przy kazdym kliku pobiera wszystkie dane z wszystkich linkow menu i w rezultacie w divie wyswietla mi drugi raz strone glowna :]..

12. Dziudek napisał(a):
12 kwietnia 2008, 15:21:15

@jimmy0699 – no, teraz już jaśniej ;) Osobiście proponowałbym stworzenie sobie skryptu php, który w zależności od parametru x w adresie wyświetli tylko te dane, które mają się pojawić w divie na stronie głównej – bez żadnych nagłówków itp. Czyli wyświetli tylko to co jest rzeczywiście potrzebne :)

13. jimmy0699 napisał(a):
12 kwietnia 2008, 15:36:25

Tak tez jest zrobione, jedyny problem w tym ze jesli w tej petli robi sie JS do obslugi tegoz menu. i definiuje je tak:
var menu_ajax = $$('.menu');
oraz dalej
menu_ajax.addEvent('click', function(e) { // tu zapytanie Ajax... }
to w tym nie gra cos i po kliknieciu byle gdzie pobiera ajaxem wszystkie mozliwosci parametru x.
Nie mecze zbytnio??

14. Dziudek napisał(a):
12 kwietnia 2008, 15:50:17

@jimmy0699 – spróbuj zamiast menu_ajax.addEvent poprzez:

menu_ajax.each(function(el,i){el.addEvent("click",function(){/**kod funkcji**/});});

15. maly_john napisał(a):
30 kwietnia 2009, 11:50:45

Witam,
po analizie przykładów i próbie odpalenia tego na serwerze lokalnym wszystko fajnie działa…. niestety do tego czasu. Następnie spróbowałem przetestować powyższe przykłady na serwerze ftp.. i tu w firebugu wyrzuca w konsoli błąd 400 bad request:
POST http://www.radwansport.pl/test/CMS/home.php
400 Bad Request 177ms
Ciekawe jest to że jeżeli przepisze do powyższy url do przeglądarki od razu odpala odpowiedni skrypt home.php.
Proszę o pomoc, dziękuję

16. aaa napisał(a):
17 grudnia 2009, 17:03:09

wszystkie przykłady padły, pojawia się error :/

Dodaj komentarz:

Textile Lite włączony ( szczegółowy opis znaczników ):
*strong* | # lista numerowana | * lista wypunktowana | _em_ | __italic__ | "link":http:// | bq. cytat.