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 |
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 |
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:
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%

podany skrypt nie działa
poprawki do skryptu:
HTML / linia 8
>>
AJAX:
var bid = document.getElementById(‘mid’).value;
>>
var mid = document.getElementById(‘mid’).value;
Pozdrawiam
Tak, mój błąd, literówka. Dokonałem kilka poprawek i już powinno wszystko śmigać.
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() !
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.
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.
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.
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:
Twój magic_quotes niczym poza ‘ czy ” się nie zajmie… Naprawdę Arku – testowałem, wiem.
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
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
no prykro mi bardzo ale to u mnie nie działa, także szkoda czasu
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
teraz śmiga ładnie
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;)
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
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.’;
?>
a formularz, ja korzystałem z tego przy robieniu komercyjnego portalu i wszystko śmigało jak trzeba
Jak później pobrać dane value z drugiego selecta?
$_POST zwraca mi wypisane wartości, a nie value.
Proszę o odpowiedź na maila.
zmienna $_POST['model'] zwraca wartość drugiego selecta
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
wystarczy dodać warunek
if(!empty($mid)) {
poprawiłem kod pliku modele.php
A jak zrobić to samo tylko z trzema polami?
[...] 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 [...]
Zapraszam do lektury http://blog.tobiasz.org/2010/01/ajax-3-powiazane-pola-select/
Jak zauważyłem brak ponumerowanych linków z kontynuacją tematu. W poprzedniej wersji bloga występowały. Szkoda
dzięki, już poprawiłem