Ajax w jQuery

Obsługa Ajaxa w jQuery jest jak zwykle bajecznie prosta. W poniższym artykule poznamy różne techniki i zastosowania tej wybitnej metody :).
Z rozdziału o ajaxie wiemu już czym to "coś" jest i jak to obsłużyć w czystym JS. Wiemy też, że nie jest to najłatwiejszą czy najwygodniejszą rzeczą na świecie (dzięki IE :)). Nie w jquery. Tutaj sprawa wygląda o wiele prościej - o czym przekonamy się za chwilę.

Do najprostszych metody jQuery służących do obsługi ajaxa należą:

$.get(adres_skryptu, data_wysylana, funkcja_zwrotna)


$.get(
    "zapisz_do_bazy.php",
    {
        imie: "Johny",
        nazwisko: "Bravo"
    },
    function(dane){
        alert("Dane otrzymane: " + dane);
    }
);

//ta sama metoda zapisana ale bardziej upakowana
$.get("zapisz_do_bazy.php", {imie: "Johny", nazwisko: "Bravo"}, function(dane) {alert("Dane otrzymane: " + dane) );

Poza adresem do skryptu na serwerze reszta atrybutów jest opcjonalna. Nikt nie każe nam wysyłać ani danych ani wykonywać żadnych akcji po otrzymaniu odpowiedzi z serwera.

Bardzo podobne działanie ma metoda $.post, jednak jak sama nazwa wskazuje wysyła ona dane za pomocą post:


$.post(
    "saveToDatabase.php",
    {
        name: "Johny",
        surname: "Bravo"
    },
    function(data){
        alert("Dane otrzymane: " + data);
    }
);

Powyższe metody mimo, że bardzo proste w użyciu, nie dają nam pełnej kontroli nad połączeniem. O wiele lepszym do tego celu jest metoda $.ajax:


$.ajax({
    type     : "POST",
    url      : "saveToDatabase.php",
    data     : {
        name : 'Marcin',
        country : 'Polska'
    },
    success: function(ret) {
        //ten fragment wykona się po pomyślnym zakończeniu połączenia - gdy dostaliśmy odpowiedź od serwera nie będącą błędem (404, 400, 500 itp)
        //atrybut ret zawiera dane zwrócone z serwera
    },
    complete: function() {
        //ten fragment wykona się po zakończeniu łączenia - nie ważne czy wystąpił błąd, czy sukces
    },
    error: function(jqXHR, errorText, errorThrown) {
        //ten fragment wykona się w przypadku BŁĘDU
        //do zmiennej errorText zostanie przekazany błąd
    }
});

Tak samo jak w przypadku wcześniejszych metod, jedynym wymaganym atrybutem jest url.

Poza url możemy określić dodatkowe atrybuty, wśród których znajdują się między innymi:

  • type - typ połączenia: POST lub GET. Domyślnym jest GET
  • data - przekazywane dane. Przykłady na stronie ukazują różne sposoby definiowania danych
  • dataType - typ danych jaki oczekujemy. Omówimy go za moment. Jeżeli nie zostanie ustawiony, jQuery spróbuje określić typ danych na podstawie tego co dostanie w odpowiedzi.
  • zdarzenia - zdarzenia związane z połączeniem

W praktyce parametrów możliwych do ustawienia jest o wiele więcej, ale większości z nich na co dzień zwyczajnie się nie używa. Warto jednak przyjrzeć się stronie http://jqapi.com/#p=jQuery.ajax i zapoznać się z kilkoma z nich.

Podstawowe funkcje zwrotne

Jak wspomniałem przed chwilą funkcja $.ajax udostępnia nam funkcje zwrotne związane z obsługą połączenia. Te najczęściej używane to:

  1. success(ret) - wywoływane po pomyślnym wysłaniu danych do skryptu (kiedy serwer nie zwrócił błędu typu 400, 404, 500 itp)
  2. error(jqXHR, textStatus, errorThrown) - wywoływane gdy nastąpi błąd w połączeniu
  3. complete - wywoływane po zakończeniu łączenia - bez względu czy zakończyło się błędem czy sukcesem

$("input#start").click(function() {
    $('#loading').show();

    $.ajax({
        type: "POST",
        url: "test.php",
        data: {
            name: 'Marcin',
            age: 'stary dziad'
        },
        success: function(msg) {
            console.log( "Dane zwrotne: " + msg );
        },
        complete: function() {
            $("#loading").hide();
        },
        error: function() {
            console.log( "Wystąpił błąd w połączniu :(");
        }
    });
});

JSON z wykorzystaniem jQUERY

Najprzyjemniejszym sposobem przesyłania danych między serwerem a przeglądarką jest zastosowanie typu danych json.


    $.ajax({
        type: "POST",   //typ połączenia na post
        url: "test.php",
        dataType : 'json', //ustawiamy typ danych na json
        data: {
            someVar1 : 'LoremIpsum',
            someVar2 : 210,
        },
        success: function(json) {
            jQuery.each(json, function(i, ob) {
                console.log(i, ob);
            });
        },
        complete: function() {
            $("#loading").hide();
        },
        error: function() {
            console.log( "Wystąpił błąd w połączeniu :(");
        }
    });

Po wysłaniu danych do skryptu na serwerze będziemy je mieli w postaci zmiennych $_POST['someVar1'] i $_POST['someVar2'].
Aby przestał teraz dane do javascript, musimy podać je umieścić w tablicy, którą zwrócimy do przeglądarki za pomocą funkcji json_encode (możemy też zapis json wypisywać z palca, ale jest to mało wygodna metoda).


<?php
    $someVar1 = (int)$_POST['someVar1'];
    $someVar2 = (int)$_POST['someVar2'];

    $result = array();
    $result['someResultVar1'] = 'Po obróbce ' + $a + $a; //przykładowe działanie na zmiennej
    $result['someResultVar2'] = 'Po obróbce ' + $b + $b;

    echo json_encode($result); //przekształcamy naszą tablicę na zapis typu json
?>

Powyższy skrypt zwraca nam do jquery obiekt json:


{
    "someResultVar1": ....,
    "someResultVar2": ...
}
.

Aby go teraz obrobić skorzystamy z przedstawionej wcześniej pętli:


...
success: function(json) {
    jQuery.each(json, function(i, ob) {
        console.log(i, ob);
    });
},
...

Dynamiczne selekty z wykorzystaniem JSON

Jako przykład wykorzystania powyższej wiedzy stworzymy mechanizm 2 selektów. Opcje w 2 selekcie będą zależne od tego, co wybierzemy w 1 selekcie.
Poniższy przykład pokazuje, jak taki problem rozwiązać z wykorzystaniem json:


    <select id="select1" name="gender">
        <option value="-1">Wybierz płeć</option>
        <option value="k">Kobiety</option>
        <option value="m">Mężczyźni</option>
    </select>

    <select id="select1" disabled name="personNames">
        <option value="-1">---</option>
    </select>

Mamy więc 2 selekty. Pierwszy z nich służy do wybrania płci, a drugi będzie służyć do wyboru imienia.
Po wybraniu płci w 1 selekcie, sprawdzamy czy ma ona jakąś sensowną wartość (czyli jest różna od -1) i wysyłamy ją do serwera. Następnie aktywujemy drugi selekt i za pomocą pętli dynamicznie ustawiamy jego optiony.


var $select1 = $('#select1');
var $select2 = $('#select2');

$select1.on({
    'change' : function() {
        var selectVal = $(this).find('option:selected').val();   //pobieramy wartość wybranego selekta

        if (selectVal != -1) {  //jeżeli jest inna niż -1 (czyli jeżeli został wybrany model)
            $.ajax({
                type: "POST",
                url: "test_selekta.php",
                dataType : 'json',
                data: {
                    gender : selectVal
                },
                success : function(json) {

                    $select2.prop('disabled', 0); //aktywujemy 2 selekt
                    $select2.empty(); //czyścimy go

                    $.each(json, function(i, ob) {
                       $select2.append('<option value="'+ob.value+'">'+ob.name+'</option>');
                    });

                    //ustawiamy jako wybrany pierwszy option w selekcie 2
                    $select2.find('option').eq(0).prop('selected', 1);
                },
                error: function() {
                    console.warn('wystąpił błąd');
                }
            })
        } else {
            $select2.empty();
            $select2.prop('disabled', 1);
        }
    }
});

$select1.val(-1);
$select2.prop('disabled', 1);

Oczywiście aby powyższy skrypt miał sens, musimy stworzyć skrypt test_selekta.php, który na podstawie przesłanego POST będzie wysyłał do przeglądarki json z odpowiednimi wartościami, na podstawie których tworzymy nowe optiony:


<?php
$gender = $_POST['gender'];

$names = Array();

$names['m'] = Array();
$names['m'][0] = Array('name'=>'Arnold',    'value'=>'1');
$names['m'][1] = Array('name'=>'Bartek',    'value'=>'2');
$names['m'][2] = Array('name'=>'Darek',     'value'=>'3');
$names['m'][3] = Array('name'=>'Kamil',     'value'=>'4');
$names['m'][4] = Array('name'=>'Michał',    'value'=>'5');

$names['k'] = Array();
$names['k'][0] = Array('name'=>'Ania',      'value'=>'1');
$names['k'][1] = Array('name'=>'Beata',     'value'=>'2');
$names['k'][2] = Array('name'=>'Kamila',    'value'=>'3');
$names['k'][3] = Array('name'=>'Patrycja',  'value'=>'4');
$names['k'][4] = Array('name'=>'Zenona',    'value'=>'5');

echo json_encode($names[$gender]); ?>