Ajax: powiązane pola select

Autor: Arkadiusz Tobiasz 7 września 2008

Nieraz w serwisach internetowych widziałeś dynamiczne pola select, które uaktywniały się po wyborze opcji z pierwszego selecta. Jeśli chcesz mieć coś takiego na swojej stronie, to ten wpis jest dla Ciebie. Postaram się tutaj krok po kroku pokazać jak to zrobić.

Zacznijmy od prostego formularza w html-u:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<form>
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2" />
      <title>Prosta strona HTML</title>
      </head>
      <body>
      <form>
        <table width="300" border="0">
          <tr>
            <td width="200">
          <select name="mid" id="mid">
              <option value="">Wybierz markę</option>
              <option value="1">Audi</option>
              <option value="2">BMW</option>
            </select>
          </td>
            <td width="100">
          <select name="model" id="model">
              <option value="">Wybierz model</option>
              <option value="1">A3</option>
              <option value="2">A4</option>
          <option value="2">323</option>
            </select>
          </td>
          </tr>
        </table>
      </form>
      </body>
      </html>

Jak widzimy w powyższym kodzie kiedy wybierzemy daną markę samochodu, dajmy na to BMW, to w modelach mamy do wyboru także modele Audi. W tym tutorialu po wyborze marki będą dostępne modele tylko wybranej marki.

Swój skrypt napiszemy w PHP wykorzystując MySQL. W tym celu musimy utworzyć dwie tabele, pierwszą, w której będziemy trzymać dane dotyczące marek samochodu oraz drugą z odpowiednimi modelami samochodów.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
CREATE TABLE `marki` (
`id` int(9) NOT NULL AUTO_INCREMENT,
`marka` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin2 ;

INSERT INTO `marki` VALUES(1, 'Audi');
INSERT INTO `marki` VALUES(2, 'BMW');

CREATE TABLE `modele` (
`id` int(9) NOT NULL AUTO_INCREMENT,
`mid` int(9) NOT NULL DEFAULT '0',
`model` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY  (`id`),
KEY `mid` (`mid`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin2 ;

INSERT INTO `modele` VALUES(1, 1, 'A3');
INSERT INTO `modele` VALUES(2, 1, 'A4');
INSERT INTO `modele` VALUES(3, 2, '320');
INSERT INTO `modele` VALUES(4, 2, '323');
INSERT INTO `modele` VALUES(5, 2, '324');

Krótki komentarz, tworzymy powyżej dwie tabele marki i modele, tabela modele jest powiązana z tabelą marki za pomocą klucza mid.

Przyszedł czas na modyfikację kodu HTML i przerobienie go na skrypt php, który nazwiemy samochody.php. Musimy linijki 12-16 przerobić w taki sposób, aby dane były pobierane z bazy danych. A więc fragment:

1
2
3
4
5
<select id="mid" name="mid">
<option>Wybierz markę</option>
 <option value="1">Audi</option>
<option value="2">BMW</option>
 </select>

zamieniamy na:

1
2
3
4
5
6
7
8
9
10
11
12
      <?php
        include("config.php");
        echo "<select name=\"mid\" onchange=\"ajaxFunction()\" id=\"mid\" width=\"25\">"
        ."<option value=\"\">--wybierz--</option>";
        $result2 = mysql_query("SELECT id, marka FROM marki ORDER BY marka");
        while ($row = mysql_fetch_array($result2)) {
          $mid = intval($row['id']);
          $marka = $row['marka'];
          echo"<option value=\"".$mid."\">".$marka."</option>";
        }
        echo"</select><br>";
      ?>

W powyższym kodzie dołączyliśmy jeszcze jeden plik, który odpowiada za połączenie z bazą danych. Plik config.php wygląda następująco:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
      <?php
       
      $sql_host = "localhost";        // host bazy danych, najczesciej localhost
      $sql_user = "tobiasz_arek";  // uzytkownik bazy danych
      $sql_password = "haselko";  // haslo do bazy danych
      $sql_baza = "tobiasz_auto"; // nazwa bazy danych, z ktorej bedzie korzystal portal
      $prefix = "toar";    // prefix uzywany dla tabel korzystajacych z systemu ToAr

      /* Polaczenie z MySQL'em */
      $baza = mysql_connect($sql_host, $sql_user, $sql_password);
        if ($baza) {
      /* Jezeli polaczenie zostalo nawiazane wybieramy baze danych, z ktorej korzysta strona */
          $wynik = mysql_select_db($sql_baza);
        if($wynik) {
        /* narzucamy odpowiednie kodowanie dla clienta i polaczenia */
         mysql_query('SET character_set_connection=latin2');
         mysql_query('SET character_set_client=latin2');
         mysql_query('SET character_set_results=latin2');
        }
      }
      ?>

Po zapisaniu tych dwóch plików i wrzuceniu na serwer nasze marki samochodów powinni się wyświetlać, więc teraz czas na zrobienie dynamicznego generowania modeli. W kodzie selecta jest odwołanie do funkcji ajaxFunction(), dlatego teraz zajmiemy się nią. Na początku w sekcji musimy dodać plik Javascriptu:

1
2
3
4
5
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2" />
      <title>Prosta strona HTML</title>
      <script language="javascript" type="text/javascript" src="ajax.js"></script>
      </head>

Plik, który musimy stworzyć to ajax.js, jego struktura prezentuje się następująco:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 function ajaxFunction(){
 var ajaxRequest;

try{
 ajaxRequest = new XMLHttpRequest();
 } catch (e){
 try{
 ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
 } catch (e) {
 try{
 ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
 } catch (e){
 alert("Your browser broke!");
 return false;
 }
 }
 }

ajaxRequest.onreadystatechange = function(){
 if(ajaxRequest.readyState == 4){
 var ajaxDisplay = document.getElementById('ajaxDiv');
 ajaxDisplay.innerHTML = ajaxRequest.responseText;
 }
 }
 var mid = document.getElementById('mid').value;
 var queryString = "?mid=" + mid;
 ajaxRequest.open("GET", "modele.php" + queryString, true);
 ajaxRequest.send(null);
 }

W linijkach 4-17 jest tzw. przechwytywanie wyjątków, które wyświetli odpowiedni komunikat jeżeli przeglądarka nie będzie w stanie wykonać skryptu. Kolejne linijki odpowiadają za przechwycenie wartości wybranego pierwszego selecta i wygenerowanie nowego, który znajduje się w pliku modele.php. Skrypt ten pobiera id wybranej marki samochodu za pomocą parametru $_GET['mid']. W związku z tym najpierw w naszym pliku samochodu.php zmienimy kod drugiego selecta na:

1
2
3
      <td width="100">
      <div id='ajaxDiv'></div>
      </td>

W sekcji ajaxDiv po wybraniu marki samochodu pojawią się do wyboru jej modele, ale najpierw musimy stworzyć odpowiedni plik modele.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
      <?php
      $mid = $_GET['mid'];
      if(!empty($mid)) {
        include("config.php");
        $dropdown = "<select name=\"model\"  id=\"model\" width=\"25\">";
        $dropdown .= "<option value=\"\">--wybierz--</option>";

        $result2 = mysql_query("SELECT id, model FROM modele WHERE mid=".$mid." ORDER BY model");

        while ($row = mysql_fetch_array($result2)) {
          $id = intval($row['id']);
          $model = $row['model'];
          $dropdown .= "<option value=\"".$id."\">".$model."</option>";
        }
        $dropdown .= "</select><br>";
      echo $dropdown;
}
      ?>

Jeszcze na wszelki wypadek kod pliku samochody.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2" />
      <title>Prosta strona HTML</title>
      <script language="javascript" type="text/javascript" src="ajax.js"></script>
      </head>
      <body>
      <form>
        <table width="300" border="0">
          <tr>
            <td width="200">
        <?php
        include("config.php");
        echo "<select name=\"mid\" onchange=\"ajaxFunction()\" id=\"mid\" width=\"25\">"
        ."<option value=\"\">--wybierz--</option>";
        $result2 = mysql_query("SELECT id, marka FROM marki ORDER BY marka");
        while ($row = mysql_fetch_array($result2)) {
          $mid = intval($row['id']);
          $marka = $row['marka'];
          echo"<option value=\"".$mid."\">".$marka."</option>";
        }
        echo"</select><br>";
      ?>
          </td>
            <td width="100">
          <div id='ajaxDiv'></div>
      </td>
          </tr>
        </table>
      </form>
      </body>
      </html>

W taki oto sposób udało się wykonać nam dynamicznego selecta ;) Mam nadzieję, że nigdzie nie popełniłem błędu, bo miejscami pisałem z głowy.

Popularity: 100%



WP Oceny
3
3
0
0
13
0
8
7


Komentarze: 26

  1. podany skrypt nie działa

  2. poprawki do skryptu:

    HTML / linia 8

    >>

    AJAX:
    var bid = document.getElementById(‘mid’).value;
    >>
    var mid = document.getElementById(‘mid’).value;

    Pozdrawiam

  3. Tak, mój błąd, literówka. Dokonałem kilka poprawek i już powinno wszystko śmigać.

  4. Mori mówi:

    Wybacz, bo tylko rzuciłem okiem… Nigdzie nie sprawdzasz stringów od usera? :/ Wstyd! I zła praktyka, bardzo zła.

    Używaj mysql_real_escape_string() !

  5. ale to są pola select i user nie może użyć dowolnego ciągu znaków, jest ograniczony tylko i wyłącznie do listy rozwijanej.

  6. Mori mówi:

    Wybacz, Arkadiuszu, ale bzdura. Każdy może dowolnie zmodyfikować sobie zawartość POSTa w momencie przesyłania – musi mieć tylko odpowiednie narzędzia. Nie mówiąc o tym, że ja mogę sobie w Operze wyedytować kod Twojej strony, wczytać do lokalnie i mieć w SELECT’cie dowolne rzeczy.

    Hej, wrzuć to gdzieś live – takie demo. I np. zapisuj dokładnie string, jaki zostanie przesłany przez SELECT’a. Nie ingeruj w niego, nic… I zobaczymy, czy da się przesłać tylko to, co jest na liście.

  7. Tylko na moim serwerze to nie zadziała, bowiem moje ustawienia PHP mają odblokowaną opcję Magic Quotes, która automatycznie dodaje znacznik prawego ukośnika do apostrofów i cudzysłowów.

  8. Mori mówi:

    Tak czy tak – zostało udowodnione, że magic quotes nie wystarcza. Do “zabicia” zapytania wystarczą i inne znaki.

    Zresztą… Zaiwanione z opisu funckji na PHP.net:

    mysql_real_escape_string() calls MySQL’s library function mysql_real_escape_string, which prepends backslashes to the following characters: \x00, \n, \r, \, ‘, ” and \x1a.

    Twój magic_quotes niczym poza ‘ czy ” się nie zajmie… Naprawdę Arku – testowałem, wiem.

  9. lukas mówi:

    A widzisz Mori ja właśnie tego szukałem, jeszcze nie zrobiłęm pod siebie ale zaraz próbuje. I nie interesuje mnie zabezpieczenie skryptu. Dopiero się ucze i wole aby był on czytelny na tyle abym mógł zrozumieć zasade działania.
    A w momencie kiedy dojde do wprawy zaczne zabezpieczać skrypt.
    W końcy w szkole też cię uczyli dodawać od 1+1 a nie od razu jakieś wyrażenia z całkami itd.
    Jak dla mnie przydatne info.
    A nigdzie nie jest napisane uwaga super bezpieczny skrypt itd.
    Pozdr

  10. Tadek mówi:

    Bardzo poprosze o wersje live. Tez sie dopiero ucze i nie chce smigac ;/ albo bez wielkiego czarowania co sie po kolei robi tylko gotowe pliki. Pozdrawiam

  11. lukas mówi:

    no prykro mi bardzo ale to u mnie nie działa, także szkoda czasu

  12. już poprawiłem, zła nazwa id w kodzie było. Działający skrypt można podejrzeć pod adresem poniżej
    http://tobiasz.org/skrypty/ajax/samochody.php

  13. lukas mówi:

    teraz śmiga ładnie ;)

  14. Sisko mówi:

    A wiecie moze jak zrobic aby wyswietlone w ten sposob dane mozna bylo zapisac do bazy danych za pomoca php?Bo jakos nie moge sobie z tym poradzic. Z gory dzieki za info. Skrypt ogolnie super;)

  15. jak w zwykłym formularzu, czyli po wysłaniu tego za pomocą metody POST
    powinniśmy mieć zmienną $_POST['model'], która będzie zawierać id danego modelu

  16. Sisko mówi:

    Robie to tak i niestety wyskakuje mi ze nie sa wypelnione wszystkie pola czyli tak jakby nie czyta mi tej zmniennej z formularza:/

    <?php

    //utworzenie nazw zmiennych
    $model=$_POST['model'];
    $marka=$_POST['marka'];
    $tytul=$_POST['tytul'];
    $opis=$_POST['opis'];
    $budzet=$_POST['budzet'];
    $platnosc=$_POST['platnosc'];

    if(!$model || !$marka || !$tytul || !$opis || !$budzet || !$platnosc)
    {
    echo ‘Nie podano wszystkich danych.’
    .’Wróć i spróbuj ponowanie.’;
    exit;
    }

    if (!get_magic_quotes_gpc())
    {
    $model = addslashes($model);
    $marka = addslashes($marka);
    $tytul = addslashes($tytul);
    $opis = addslashes($opis);
    $budzet = addslashes($budzet);
    $platnosc = addslashes($platnosc);
    }
    @$db = new mysqli(‘localhost’ , ‘root’ , ‘vertrigo’ , ‘ogloszenia’);

    if (mysqli_connect_errno())
    {
    echo ‘Błąd: : Połączenie z bazą danych nie powiodło się.’;
    exit;
    }

    $zapytanie = insert into ogloszenia (kategoriaid, tytul , opis , budzet , platnosc) values (‘.$model.’ , ‘.$marka.’ , ‘.$tytul.’ , ‘.$opis.’ , ‘.$budzet.’ , ‘.$platnosc.’);
    $wynik = $db->query($zapytanie);
    if ($wynik)
    echo $db->affected_rows.’ogłoszenie dodano do bazy.’;
    ?>

  17. a formularz, ja korzystałem z tego przy robieniu komercyjnego portalu i wszystko śmigało jak trzeba ;)

  18. Piter mówi:

    Jak później pobrać dane value z drugiego selecta?
    $_POST zwraca mi wypisane wartości, a nie value.

    Proszę o odpowiedź na maila.

  19. zmienna $_POST['model'] zwraca wartość drugiego selecta

  20. robbys mówi:

    Niestety nie działa :-( Pojawia się takie ostrzerzenie po poworcie do “wybierz” w pierwszym polu wyboru. Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in /home/tobiasz/domains/tobiasz.org/public_html/skrypty/ajax/modele.php on line 10

  21. wystarczy dodać warunek

    if(!empty($mid)) {

    poprawiłem kod pliku modele.php

  22. widaw mówi:

    A jak zrobić to samo tylko z trzema polami?

  23. [...] pola select, a nawet więcej. Tutorial ten będzie kontynuacją opublikowanego ponad rok temu wpisu Ajax: powiązane pola select, więc zanim przystąpisz do czytania dalszej części wpisu wykonaj wszystkie rzeczy w podanym [...]

  24. robbys mówi:

    Jak zauważyłem brak ponumerowanych linków z kontynuacją tematu. W poprzedniej wersji bloga występowały. Szkoda :-(

  25. dzięki, już poprawiłem ;)

Odpowiedz

Arkadiusz Tobiasz student Akademii Ekonomicznej im. Karola Adamieckiego w Katowicach na specjalnościach informatyka ekonomiczna oraz rachunkowość. Więcej...

Wordpress 3.0

Ostatnio mało się pojawia, gdyż jestem w trakcie kończenia studiów. Nie spodziewałem się tego, że będzie tyle przy tym roboty [...]

jQuery: sprawdzanie dostępności

W dzisiejszym wpisie zaprezentuję Wam jak z wykorzystaniem biblioteki jQuery napisać sprawdzanie dostępności np. loginu przy rejestracji na stronie. Funkcja [...]

jQuery: powielanie pól formularza

Dzięki jQuery możemy powielać niektóre pola naszego formularza w bardzo prosty sposób. Wartości wpisywane do tych pól są zapisywane wtedy [...]

jQuery: zliczanie i limit znaków

Jakiś czas temu pokazałem jak przy użyciu JavaScriptu zrobić prosty licznik znaków wpisanych do pola typu textarea oraz jak ograniczyć [...]

  Sponsorzy bloga
  Reklama na blogach - Brand New Media
Reklama na blogach - Blogvertising.pl
Silesia City Center on Facebook