Powiązane pola Select wykorzystujące Ajaxa

W serwisie dhtmlgoodies.com dostępny jest skrypt "AJAX chained select" - otrzymujemy dwa pola typu SELECT, z tym że opcje dostępne dla drugiego pola SELECT zależą od opcji wybranej w pierwszym polu i są pobierane dynamicznie za pomocą AJAXa.

Jak tego użyć

  • Tworzymy pusty katalog na serwerze
  • Umieszczamy tam plik ajax.js
  • Tworzymy plik index.php i getCities.php o kodzie odpowiednio:
<script type="text/javascript" src="ajax.js"></script>
<script type="text/javascript">
var ajax = new sack();

function getCityList(sel)
{
	var countryCode = sel.options[sel.selectedIndex].value;
	document.getElementById('dhtmlgoodies_city').options.length = 0;	// Empty city select box
	if(countryCode.length>0){
		ajax.requestFile = 'getCities.php?countryCode='+countryCode;	// Specifying which file to get
		ajax.onCompletion = createCities;	// Specify function that will be executed after file has been found
		ajax.runAJAX();		// Execute AJAX function
	}
}

function createCities()
{
	var obj = document.getElementById('dhtmlgoodies_city');
	eval(ajax.response);	// Executing the response from Ajax as Javascript code	
}

		
</script>
<form action="" method="post">
<table>
	<tr>
		<td>Country: </td>
		<td><select id="dhtmlgoodies_country" name="dhtmlgoodies_country" onchange="getCityList(this)">
			<option value="">Select</option>
			<option value="dk">Denmark</option>
			<option value="no">Norway</option>
			<option value="us">US</option>
		</select>
		</td>
	</tr>
	<tr>
		<td>City: </td>
		<td><select id="dhtmlgoodies_city" name="dhtmlgoodies_city">
		
		</select>
		</td>
	</tr>
</table>
</form>
getCities.php:
<?php
 
 if(isset($_GET['countryCode'])){
   
   switch($_GET['countryCode']){
     
     case "no":
       echo "obj.options[obj.options.length] = new Option('Bergen','1');
";
       echo "obj.options[obj.options.length] = new Option('Haugesund','2');
";
       echo "obj.options[obj.options.length] = new Option('Oslo','3');
";
       echo "obj.options[obj.options.length] = new Option('Stavanger','4');
";
       
       break;
     case "dk":
       
       echo "obj.options[obj.options.length] = new Option('Aalborg','11');
";
       echo "obj.options[obj.options.length] = new Option('Copenhagen','12');
";
       echo "obj.options[obj.options.length] = new Option('Odense','13');
";
       
       break;
     case "us":
       
       echo "obj.options[obj.options.length] = new Option('Atlanta','21');
";
       echo "obj.options[obj.options.length] = new Option('Chicago','22');
";
       echo "obj.options[obj.options.length] = new Option('Denver','23');
";
       echo "obj.options[obj.options.length] = new Option('Los Angeles','24');
";
       echo "obj.options[obj.options.length] = new Option('New York','25');
";
       echo "obj.options[obj.options.length] = new Option('San Fransisco','26');
";
       echo "obj.options[obj.options.length] = new Option('Seattle','27');
";
       
       break;
   }  
 }
 
 ?>
I gotowe. Otwarcie w przeglądarce index.php wyświetli testowy formularz. Wybranie wartości w pierwszym polu udostępni określone opcje w drugim.

Generowanie opcji z wykorzystaniem bazy danych

W powyższym przykładzie w pierwszym polu wybieramy kraj, a w drugim wyświetlają się miasta z danego kraju. Tak więc potrzebujemy tabeli zawierającej miasta przypisane do danego kraju. Oto kod SQL tworzący w MySQL potrzebną tabelę:
CREATE TABLE test (
id int(10) unsigned NOT NULL auto_increment,
kraj varchar(20) default NULL,
miasto varchar(100) default NULL,
PRIMARY KEY  (id))
ENGINE=MyISAM DEFAULT CHARSET=utf8;
Dodajemy kilka wpisów:
INSERT INTO test (kraj, miasto) VALUES ('Polska', 'Warszawa');
INSERT INTO test (kraj, miasto) VALUES ('Polska', 'Kraków');
INSERT INTO test (kraj, miasto) VALUES ('Polska', 'Wisła');
INSERT INTO test (kraj, miasto) VALUES ('Niemcy', 'Berlin');
INSERT INTO test (kraj, miasto) VALUES ('Niemcy', 'Bishofshofen');
Modyfikujemy index.php do postaci:
W poniższych przykładach wykorzystano prostą klasę do obsługi połączenia z bazą danych. Jeżeli chcesz zastosować komponent we własnych skryptach odpowiednio zmodyfikuj kod odpowiedzialny za pobieranie danych z bazy danych.
<script type="text/javascript" src="ajax.js"></script>
<script type="text/javascript">
var ajax = new sack();

function getCityList(sel)
{
	var countryCode = sel.options[sel.selectedIndex].value;
	document.getElementById('dhtmlgoodies_city').options.length = 0;	// Empty city select box
	if(countryCode.length>0){
		ajax.requestFile = 'getCities.php?countryCode='+countryCode;	// Specifying which file to get
		ajax.onCompletion = createCities;	// Specify function that will be executed after file has been found
		ajax.runAJAX();		// Execute AJAX function
	}
}

function createCities()
{
	var obj = document.getElementById('dhtmlgoodies_city');
	eval(ajax.response);	// Executing the response from Ajax as Javascript code	
}

		
</script>
<form action="" method="post">
<table>
	<tr>
		<td>Country: </td>
		<td><select id="dhtmlgoodies_country" name="dhtmlgoodies_country" onchange="getCityList(this)">
		<option value="">Wybierz</option>
		<?PHP
		include 'mysql.class.php';
		$a = new mysql_db();
		$a->connect('localhost', 'root', '', 'test2');
		$q = $a->query_select("SELECT DISTINCT kraj FROM test");
		foreach($q as $i)
			{
			echo '<option value="'.$i['kraj'].'">'.$i['kraj'].'</option>';
			}
		$a->destruct();
		?>
		</select>
		</td>
	</tr>
	<tr>
		<td>City: </td>
		<td><select id="dhtmlgoodies_city" name="dhtmlgoodies_city">
		
		</select>
		</td>
	</tr>
</table>
</form>
Zamiast statycznej listy opcji dla pierwszego pola SELECT pobraliśmy je z bazy danych. W tym przypadku mamy zapytanie:
SELECT DISTINCT kraj FROM test
Pobieramy unikalną (bez powtórzeń) listę krajów z tabeli. Zastosowana przeze mnie prosta klasa nakładkowa od razu zwraca tablicę asocjacyjną z wynikiem więc możemy wyświetlić poszczególne kraje w pętli. Reszta bez zmian. Natomiast getCities.php wygląda tak:
<?php

if(isset($_GET['countryCode']))
	{
	include 'mysql.class.php';
	$a = new mysqli_db();
	$a->connect('localhost', 'root', '', 'test2');
	$q = $a->query_select("SELECT id,miasto FROM test WHERE kraj = '".mysql_real_escape_string($_GET['countryCode'])."'");
	foreach($q as $i)
		{
		echo "obj.options[obj.options.length] = new Option('".$i['miasto']."','".$i['id']."');
";
		}
	$a->destruct();
	}
?>
Żądanie AJAXa przekaże zmienną $_GET['countryCode'] zawierającą nazwę miasta, tak więc możemy napisać odpowiednie zapytanie, a następnie w pętli wyświetlić odpowiedni kod JavaScript dodający opcje do drugiego SELECTa.

Powyższy kod łatwo dostosować do innych powiązanych danych np. kategoria-podkategoria może być zrobiona identycznie (kategoria - kraj, podkategoria - miasto):
CREATE TABLE kategorie (
id int(10) unsigned NOT NULL auto_increment,
nazwa varchar(20) default NULL,
parent_cat int(10) unsigned NOT NULL,
PRIMARY KEY  (id))
ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO kategorie (nazwa, parent_cat) VALUES ('Główna 1', 0);
INSERT INTO kategorie (nazwa, parent_cat) VALUES ('Główna 2', 0);
INSERT INTO kategorie (nazwa, parent_cat) VALUES ('Pod1 Główna 1', 1);
INSERT INTO kategorie (nazwa, parent_cat) VALUES ('Pod2 Główna 1', 1);
INSERT INTO kategorie (nazwa, parent_cat) VALUES ('Pod3 Główna 2', 2);
index.php:
<?PHP
header('Content-Type: text/html; charset=utf-8');
?>
<script type="text/javascript" src="ajax.js"></script>
<script type="text/javascript">
var ajax = new sack();

function getCityList(sel)
{
	var countryCode = sel.options[sel.selectedIndex].value;
	document.getElementById('dhtmlgoodies_city').options.length = 0;	// Empty city select box
	if(countryCode.length>0){
		ajax.requestFile = 'getCities.php?countryCode='+countryCode;	// Specifying which file to get
		ajax.onCompletion = createCities;	// Specify function that will be executed after file has been found
		ajax.runAJAX();		// Execute AJAX function
	}
}

function createCities()
{
	var obj = document.getElementById('dhtmlgoodies_city');
	eval(ajax.response);	// Executing the response from Ajax as Javascript code	
}

		
</script>
<form action="" method="post">
<table>
	<tr>
		<td>Country: </td>
		<td><select id="dhtmlgoodies_country" name="dhtmlgoodies_country" onchange="getCityList(this)">
		<option value="">Wybierz</option>
		<?PHP
		include 'mysql.class.php';
		$a = new mysql_db();
		$a->connect('localhost', 'root', '', 'test2');
		$q = $a->query_select("SELECT id, nazwa FROM kategorie WHERE parent_cat = 0");
		foreach($q as $i)
			{
			echo '<option value="'.$i['id'].'">'.$i['nazwa'].'</option>';
			}
		$a->destruct();
		?>
		</select>
		</td>
	</tr>
	<tr>
		<td>City: </td>
		<td><select id="dhtmlgoodies_city" name="dhtmlgoodies_city">
		
		</select>
		</td>
	</tr>
</table>
</form>
getCities.php:
<?php
header('Content-Type: text/html; charset=utf-8');
if(isset($_GET['countryCode']))
	{
	include 'mysql.class.php';
	$a = new mysql_db();
	$a->connect('localhost', 'root', '', 'test2');
	$q = $a->query_select("SELECT id, nazwa FROM kategorie WHERE parent_cat = '".mysql_real_escape_string($_GET['countryCode'])."'");
	foreach($q as $i)
		{
		echo "obj.options[obj.options.length] = new Option('".$i['nazwa']."','".$i['id']."');
";
		}
	$a->destruct();
	}
?>
Tutaj przyjeliśmy że kategoriom głównym przypisujemy wartość "0" dla pola parent_cat. Dla podkategori pole parent_cat zawiera numer ID kategorii nadrzędnej.
RkBlog

PHP w Akcji, 23 July 2008

Comment article
Comment article RkBlog main page Search RSS Contact