You are not logged in.

  • Login

Wednesday, April 27th 2011, 8:12pm

Tags

abhängigkeit, AJAX, auswahl, dependency, Feld, nachladen, Select

Abstract

Dieses Tutorial vermittelt die Kenntnisse um beliebig viele Select-Felder mit AJAX zu verbinden.

Article

1. Code


index.html

HTML Code

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
34
35
36
37
38
39
40
41
42
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" xml:lang="de">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>Select-Auswahl mit AJAX Abhängigkeit</title>
<script type="text/javascript" src="script.js"></script>
<style type="text/css">
<!--
/* demostyle - not necessary to make it work*/
body{font-size:11pt;font-family:Verdana,Arial,Sans}
//-->
</style>
</head>
<body onload="sendRequest(null, 'elem1')">
 
<form method="post" action="" id="ajaxSelect">
 
	<table>
		<tr id="elem1" style="display:none">
			<td>HauptKategorie:</td>
			<td><select name="hauptkategorie" size="4" onchange="sendRequest(this, 'elem2')"><option value=""></option></select></td>
		</tr>
		<tr id="elem2" style="display:none">
			<td>UnterKategorie:</td>
			<td><select name="unterkategorie" size="4" onchange="sendRequest(this, 'elem3')"><option value=""></option></select></td>
		</tr>
		<tr id="elem3" style="display:none">
			<td>UnterUnterKategorie1:</td>
			<td><select name="unterunterkategorie" size="4" onchange="sendRequest(this, 'elem4')"><option value=""></option></select></td>
		</tr>
		<tr id="elem4" style="display:none">
			<td>UnterUnterKategorie2:</td>
			<td><select name="unterunterkategorie" size="4" onchange="sendRequest(this)"><option value=""></option></select></td>
		</tr>
	</table>
 
	<div>
		<input type="submit" />
	</div>
</form>
 
</body></html>


script.js

JavaScript Code

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
 * clears a select form element
 * 
 * @param targetSel - dom reference to the select element
 */
function clearSelect(targetSel) {
	for (var i=targetSel.length; i>=0; i--) {
		targetSel.options[i] = null;
	}
}
/**
 * sends a request under usage of a loading graphic - targettable has to be positioned relative
 *
 * @param srcref - reference to the select element with chosen data
 * @param target - form element name of target element
 */
function sendRequest(domref, target) {
	// skip if no target specified
	if(!target) return false;
 
	// save reference to next target
	if(domref) domref.followup = target;
 
	var req;
	try {
		req = window.XMLHttpRequest ? new XMLHttpRequest():
			new ActiveXObject("Microsoft.XMLHTTP");
	} catch (e) {
		// no AJAX Support
	}
	req.onreadystatechange = function() {
		if ((req.readyState == 4) && (req.status == 200)) {
			// merge empty line with response
			var data = eval('(' + req.responseText + ')');
			var targetRef = document.getElementById(target);
			var targetSel = targetRef.getElementsByTagName('select')[0];
 
			// make it visible
			targetRef.style.display = 'block';
 
			// clear old data
			clearSelect(targetSel);
 
			// fill with data from json response
			var i=0;
			for(var x in data) {
				targetSel.options[i++] = new Option(
					data[x].text, 
					data[x].id
				);
			}
 
			// clear all followups
			while(targetSel.followup) {
				targetRef = document.getElementById(targetSel.followup);
 
				// make it hidden
				targetRef.style.display = 'none';
 
				// mark next select
				targetSel = targetRef.getElementsByTagName('select')[0];
 
				// clear old data
				clearSelect(targetSel);
			}
		}
	}
 
	req.open('post', 'ajax.php');
	req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
 
	// send empty post with initial load
	req.send(domref !== null ? 'id='+domref.value+'&name='+domref.name : '');
 
	return false; // return false to avoid reload/recentering of the page
}


ajax.php
Die meisten werden in dem Umgang mit einer Datenbank vertraut sind. Die ajax.php empfängt eine $_REQUEST Variable "id" und muss eine zweidimensionales Array mit den Schlüsseln "id" und "key" zurückgeben. Auf Basis des PDO Tutorials habe ich folgenden Demo Code erstellt:

PHP Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$sql = "SELECT	id, text
	FROM	category
	WHERE	parentID = :id"; 
$stmt = MyDB::getInstance()->prepare($sql); 
$stmt->execute(array( 
	':id' => $_REQUEST['id']
));
$return = $stmt->fetchAll();
 
echo json_encode($return);
?>


Für das Demoscript habe ich folgenden Code bereitgestellt:

PHP Quellcode

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
<?php
// u can use $_POST['name'] to build your controller depending on the form name
// but in a category tree the name is not important, we just need the parent id
$id = isset($_REQUEST['id']) ? $_REQUEST['id'] : 0;
 
// (1) example array with four main categories
for($i=0; $i<4; $i++) {
	// four subcategories each
	for($j=($i*10); $j<($i*10)+3; $j++) {
		$idx = $j+1;
		$data[$i][$j] = array(
			'id' => $idx,
			'text' => sprintf('cat %d (parent:%d)', $idx, $i),
		);
 
		// with three childs eiter
		for($k=($idx*10); $k<($idx*10)+3; $k++) {
			$data[$idx][$k] = array(
				'id' => $k,
				'text' => sprintf('subcat %d (parent:%d)', $k, $idx),
			);
		}
	}
}
 
// access the childs with its parent index
$return = $data[$id];
 
echo json_encode($return);
?>


2. Abhängige Felder definieren


Das Beispiel lässt sich um beliebig viele Select-Auswahlfelder erweitern. Ihr müsst der Methode sendRequest als ersten Parameter immer this übergeben und als zweiten Parameter die ID des Container, der das abhängige Select-Feld enthält.
Am Ende der Kette - wenn also keine abhängigen Felder mehr nachgeladen werden sollen - übergebt ihr einfach gar keinen Parameter.

HTML Code

1
2
3
4
5
6
7
8
<tr id="elem1">
	<td>Haupt Kategorie:</td>
	<td><select onchange="sendRequest(this, 'elem2')"></select></td>
</tr>
<tr id="elem2">
	<td>Unter Kategorie:</td>
	<td><select></select></td>
</tr>


3. Felder nicht verstecken


Im konkreten Beispiel wurde entschieden abhängige Select-Auswahlfelder erst anzuzeigen, sobald das Elternelement die notwendige Auswahl getroffen hat. Sollte es besser ins Layout passen und ihr wollt stattdessen leere Listenelemente verwendet, so entfernt einfach die style Eigenschaft display:none. Das müsst ihr sowohl im HTML Code machen, als auch alle display Aufrufe im Quelltext entfernen.

4. Demo


Eine Live Demo findet ihr unter http://demo.easy-coding.de/ajax/select-a…x-abhaengigkeit. Des weiteren wird der kompletten Code hier als ZIP Archiv zur Verfügung gestellt: download.zip.



5. Fortsetzung


Mehr Informationen zum Datenbankbeispiel findet ihr auch hier: Select-Auswahl mit AJAX Abhängigkeit und verschiedenen Tabellen

Lexikon 4.1.5, developed by www.viecode.com