guenni
Goto Top

AutoComplete mit PHP MySQL jQuery jQueryUI JSON

Auf die Frage"Wie kann man nach Eingabe in einem Textfeld Suchvorschläge anzeigen oder ein Select-Feld füllen",

oder ähnlichen Fragen, fällt oftmals das Stichwort "AutoComplete".

Anstoss, mich selber mal mit diesem Thema zu beschäftigen, war das folgende Problem eines Forenusers:

Aus einer Tabelle mit ca. 16.000 Zeilen, sollte nach Eingabe einer PLZ ein Ort gefunden werden,

damit dieser automatisch mit der PLZ im Formular übernommen wird. Problem: Es sollte ein Select-Feld

gefüllt werden, was aber 4 und mehr Sekunden dauert. Sehr unkomfortabel.

back-to-topWas ist AutoComplete?
AutoComplete ist Bestandteil einer jQueryUI-Bibliothek, im Aufbau ähnlich einer Funktion,

und wird, wie in JavaScript üblich, mittels Punkt an ein Objekt angehangen.

Das Objekt, hier ein Textfeld, wird mittels einem Selector anhand seiner ID ermittelt.

$("#ID_des_Textfelds").autocomplete({ . . . });  

Innerhalb der geschweiften Klammern wird eine Datenquelle angegeben. Die Datenquelle kann folgendes sein:
back-to-topEin "hardcodiertes Array" im Quelltext, wobei die Syntax aber einem anderen Kontext(JSON) unterliegt.

Beispiel -> http://www.jqueryautocomplete.com/jquery-autocomplete-json-example.html

Wobei hier schnell klar wird, dass sich diese Methode, m.M. nach, eigentlich nur für einige "starre" Begriffe eignet.
back-to-topEine Datenbanktabelle, hier MySQL.
back-to-topEine CSV-Datei.

Ein weiteres, optionales Argument in AutoComplete ist die Angabe minLength: x.

Das bedeutet, dass man mindestens x Zeichen eingeben muss, um eine Suche in der Quelle zu starten.

Der Aufbau von AutoComplete in diesem Beitrag sieht dann so aus:

<script type="text/javascript">  
<!--
$(function() {
 /*
 * Der Selektor #search ist die ID des Textfelds
 */
 $("#search").autocomplete(  
	{
	  /*
	  * Angabe der Quelle
	  */
	  source: DatenQuelle,
	  /*
	  * minLength bestimmt, nach wieviel eingegebenen Zeichen die Suche starten soll
	  */
	  minLength: x
	})
});
// -->
</script>

Dann müssen noch die Pfade zu den jQuery/jQueryUI-Bibliotheken im Script eingebunden werden.

Die hier verwendeten Bibliotheken findet man unter http://jqueryui.com/download/

back-to-topDie Datensuche in einer MySQL-Tabelle oder CSV-Datei
Die Suche selber wird in einem separatem PHP-Script ausgeführt. Der Name des Scripts wird in der AutoComplete-Funktion als Datenquelle angegeben:

. . .
source: 'name_des_php-script.php',  
minLength: 2 //oder anderer Wert
. . .

Was passiert nun? Nach Eingabe der ersten beiden Ziffern einer PLZ wird das Script mit einem Parameter aufgerufen.

Der Parameter enthält dabei die beiden Ziffern. Analog dazu kann man das Script auch direkt im Browser aufrufen:

name_des_php-script.php?term=41

Anhand dieses Parameters als Suchkriterium sucht das Script in der Tabelle/CSV-Datei alle Einträge, in der die PLZ mit diesen

beiden Ziffern beginnen und gibt das Ergebnis aus. Dieser Vorgang wiederholt sich mit Eingabe jeder weiteren Ziffer,

bzw. auch nach dem Löschen einer Ziffer.

back-to-topEine Einschränkung der MySQL-Tabelle, die ich noch nicht beheben konnte:
Viele Postleitzahlen im Osten Deutschlands, z.B. Dresden (PLZ: 01307), beginnen mit einer "0".

Auch wenn das PLZ-Feld in der Tabelle als String definiert ist, weigert sich MySQL eine solche PLZ abzuspeichern,

bzw. die CSV-Datei zu importieren. Liegt vielleicht daran, dass die Felder nicht in "" eingeschlossen sind.

Die "0" wird deshalb erst im Suchergebnis der PLZ vorangestellt.

Die Eingabe "01" also findet nichts, allerdings findet die Eingabe "13" Dresden (01307) sowie Berlin (13051).

Es darf also nicht die "0" als erste Ziffer einer PLZ eingegeben werden.

In der CSV-Datei stehen die PLZ mit führender 0 drin. Hier kann die 0 als erste Ziffer eingegeben werden.

Für beide Methoden gilt:

Die gefundenen Ergebnisse werden in einem Array wiederum als Array in der JSON-Notation abgelegt.

Das gesamte Array wird mit der Funktion json_encode(array) ausgegeben.
back-to-topInfo zu den gespeicherten Daten: Die MySQL-Tabelle sowie die CSV-Datei enthalten folgende Spalten:
id
Postleitzahl
Ort
Kreisschlüssel
Kreis/Stadt
Länderschlüssel
Bundesland

Für die Richtigkeit/Vollständigkeit der Daten kann ich natürlich keine Garantie übernehmen.
back-to-topDas Script Datenquelle MySQL

<?php
$conn = new PDO("mysql:host=localhost;dbname=test", "guenni", "guenni");  
$query = "select plz, ort, kreis, bundesland from postleitzahlen where plz like '".$_REQUEST['term']."%'";  
$stmt = $conn->prepare($query);
$ok = $stmt->execute();
if($ok === false){
 print_r($stmt->errorInfo());
}else{
			while($result = $stmt->fetch(PDO::FETCH_ASSOC)){
			 if($result['plz'] < 10000){  
			  /*
				* Falls die PLZ < 10000 ist, bekommt sie eine 0 vorangestellt
				*/
			  $result['plz'] = "0".$result['plz'];  
			 }
			 $results = array("label" => $result["plz"]." / ".$result["ort"]." / ".$result["kreis"]." / ".$result["bundesland"]);  
			}
			echo json_encode($results);
		 }
?>

back-to-topDas Script Datenquelle CSV-Datei

<?php
 $datei = "postleitzahlen2.csv";  
 $f = fopen($datei, "r");  
 $orte = array();
 $length = strlen($_REQUEST['term']);  
 while($line = fgetcsv($f, 0, ";")){  
  if(substr($line[1], 0, $length) == $_REQUEST['term']){  
	 /*
	 * Arrayelemente in $line
	 * 0 = id
	 * 1 = Postleitzahl
	 * 2 = Ort
	 * 3 = Kreisschlüssel
	 * 4 = Kreis/Stadt
	 * 5 = Länderschlüssel
	 * 6 = Bundesland
	 */
	 $orte = array("label" => $line[1]." / ".$line[2]." / ".$line[4]." / ".$line[6]);  
	}
 }
 fclose($f);
 echo json_encode($orte);
?>

back-to-topEin Formularscript zum Suchen

<!DOCTYPE HTML>
<html>
<head>
<title>Ortsuche mit AutoComplete</title>
<!-- Pfade zu den CSS Dateien -->
<link rel="stylesheet" href="jquery_ui/css/ui-lightness/jquery-ui-1.10.4.custom.css"/>  
<link rel="stylesheet" href="jquery_ui/css/ui-lightness/jquery-ui-1.10.4.custom.min.css"/>  
<!-- Pfade zu den jQuery/jQuery-ui Dateien -->
<script src="jquery_ui/js/jquery-1.10.2.js" type="text/javascript"></script>  
<script src="jquery_ui/js/jquery-ui-1.10.4.custom.js" type="text/javascript"></script>  
<script src="jquery_ui/js/jquery-ui-1.10.4.custom.min.js" type="text/javascript"></script>  
<script type="text/javascript">  
<!--
$(function() {
 /*
 * Der Selektor #search ist die ID des Textfelds
 */
 $("#search").autocomplete(  
	{
		 /*
		 * Angabe der Quelle
		 * Script zum Suchen in einer MySQL-Tabelle
		 * Script zum Suchen in einer CSV-Datei
		 */
		 source: 'a_1orte_source_sql.php',  
		 // source: 'a_1orte_source_csv.php', 
		 /*
		 * minLength bestimmt, nach wieviel eingegebenen Zeichen die Suche starten soll
		 */
		 minLength: 2
	})
});
// -->
</script>
</head>
<body>
<form action="" method="post">  
<p>Eingabe der Postleitzahl zur Ortssuche <input type="text" name="search_ort" id="search" size="60" /></p>  
<p>Suche starten und Ergebnis ausgeben <input type="submit" name="cmd" value="Suchen" /></p>  
</form>
<?php 
if(isset($_POST['search_ort']) && $_POST['search_ort']){  
 $orts_parameter = explode("/", $_POST['search_ort']);  
 echo "<p>Postleitzahl: ".$orts_parameter."</p>";  
 echo "<p>Ort: ".$orts_parameter[1]."</p>";  
 echo "<p>Kreis/Stadt: ".$orts_parameter[2]."</p>";  
 echo "<p>Bundesland: ".$orts_parameter[3]."</p>";  
}else{
			echo "Geben Sie eine Postleitzahl ein und wählen Sie aus der Liste einen Ort aus.";  
			}
?>
</body>
</html>
back-to-topMan kann sich ein AutoComplete auch "selberbasteln".
Das folgende Script liest die CSV-Datei ein, und übergibt die Daten via json_encode an eine JavaScript-Variable.

Alle Daten liegen dann im Browser vor, weshalb das Laden der Seite dann 1-2 Sekunden dauert.

In einem Textfeld gibt man die PLZ ein, ein Selectfeld wird dann mit den gefundenen Daten gefüllt.

<?php
 $datei = "postleitzahlen2.csv";  
 $f = fopen($datei, "r");  
 $plz_verzeichnis = array();
 $keys = array("id", "plz", "ort", "kreisschluessel", "kreis", "laenderschluessel", "bundesland");  
 while($line = fgetcsv($f, 0, ";")){  
 /*
 * Die einzelnen Zeilenarrays in einem Array speichern. Jedes Zeilenarray
 * bekommt noch die Schlüssel ($keys) für die Spalten zugewiesen 
 */
  $plz_verzeichnis = array_combine($keys, $line);
 }
 fclose($f);
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
<html>
<head>
<title>Ortssuche mit PLZ</title>
<script src="jquery-1.10.1.js" type="text/javascript"></script>  
<script type="text/javascript">  
<!-- 
var plz_verzeichnis = <?php echo json_encode($plz_verzeichnis);?>;
// -->
</script>
</head>
<body>
<form action="" method="post" name="frm">  
<p>PLZ <input type="text" name="plz" id="plz"/>  
Ort <select name="sel_ort" id="sel_ort">  
</select>
</p>
<p><input type="submit" name="cmd"/></p>  
</form>
<script type="text/javascript">  
<!--
var length = 0;
$(document).ready(function() {
 /*
 * Nach Eingabe ins Textfeld (Taste wurde gedrückt) alle bisherigen, gefundenen Orte aus dem Select entfernen
 */
 $("#plz").keydown(function(){  
  $("option").remove();  
 });
 /*
 * Nach Eingabe einer Zahl (Taste wurde losgelassen) wird die Stringlänge im Textfeld ermittelt
 * Die Stringlänge wird für die Funktion substr gebraucht
 */
 $("#plz").keyup(function() {  
  length = document.frm.plz.value.length;
  if(length == 0){return;}
  var index = 0;
 /*
 * Das Postleitzahlenverzeichnis durchsuchen. Gefunden werden alle Einträge, die mit den bisher
 * eingegebenen Zahlen übereinstimmen. Anschließend wird das Option-Feld erzeugt und ans Select angehangen
 * Die Suche im Postleitzahlenverzeichnis beginnt nach Eingabe der zweiten Zahl (length > 1)
 * 
 */
 if(length > 1){
  $.each(plz_verzeichnis, function(){
   if(length == 0){return;}
	  if(plz_verzeichnis[index]['plz'].substr(0,length) == document.frm.plz.value){  
	  var option = "<option >" +  plz_verzeichnis[index]['plz'] + " / " + plz_verzeichnis[index]['ort'] + " / " + plz_verzeichnis[index]['kreis'] + " / " + plz_verzeichnis[index]['bundesland'] + "</option>";  
	  $(option).appendTo("#sel_ort");  
	 }
	 index++;
	});
	}
 });
});
// -->
</script>
<?php 
if(isset($_POST['sel_ort'])){  
 $adresse = array();
 $keys = array("PLZ", "Ort", "Kreis/Stadt", "Bundesland");  
 $adresse = array_combine($keys, explode("/", $_POST['sel_ort']));  
 echo "<pre>";  
 print_r($adresse);
}else{
			echo "Wählen sie nach Eingabe der PLZ einen Ort aus!";  
			}
?>
</body>
</html>

Ausprobieren --> http://net-comm.de/ortsuche/index.php5
back-to-topNachtrag:

Das ist meine erste "Auseinandersetzung" mit jQuery/jQuery-ui. Falls in diesem Beitrag Unrichtigkeiten/Unvollständigkeiten enthalten sind, möge man nachsichtig sein.

Wer's besser kann/weiß: Für Tipps, Ratschläge etc. . . . wäre ich dankbar.

back-to-topAnbei noch zwei Links: Die CSV-Datei und ein MySQL-Dump zum Füllen einer Tabelle:

Link zur CSV-Datei: www.net-comm.de/ortsuche/postleitzahlen_csv.zip

Link zum MySQL-Dump: www.net-comm.de/ortsuche/postleitzahlen_sql_dump.zip


Gruß
Günni

Content-ID: 237119

Url: https://administrator.de/contentid/237119

Printed on: December 10, 2024 at 15:12 o'clock

129963
129963 Jun 30, 2016 at 17:08:36 (UTC)
Goto Top
Der Post liegt schon etwas zurück ich versuche trotzdem Hilfe zu erhalten.
Das Script funktioniert nicht mehr richtig oder ich hab irgendwas falsch gemacht.
Im gleichen Ordner sind die csv-Datei und die index.php mit dem untersten Script.
Beim öffnen der Seite index.php sind außer einige UTF-8 Codierungsfehler auch wie auf der Demo-Seite Input und Select-Feld.
Beim Eingeben von der PLZ passiert rein garnichts nicht mal dann, wenn ich auf Absenden drück.
Laut Quellcode wurden keine Daten aus der csv-Datei ausgelesen und an das Javascript übergeben denn die "keys" sind leer.

<script type="text/javascript"> 
<!-- 
var plz_verzeichnis = ;
// -->
</script>

Wäre schön wenn mir geholfen werden könnte.
Achja, Dateiberechtigung für die Postleitzahlen hab ich zwischenzeitlich auch mal durchprobiert leider ohne Erfolg.
kuddeldaddeldu
kuddeldaddeldu Aug 05, 2017 at 17:45:34 (UTC)
Goto Top
Hallo!
Ich habe ein ähnliches Problem.
Es wird nach Eingabe der PLZ keine Auswahl angezeigt (Dropdownfeld bleibt leer).
Auch bei mir bleibt "plz_verzeichnis" leer.
Anders, als bei meinem Vorschreiber bekomme ich keine Fehlermeldungen.
Und: auf der Demoseite funktioniert es tadellos - so, wie man es erwartet.

Wäre wirklich gut, wenn jemand helfen könnte, weil ich dieses klasse Script gerne in mein Formular einbauen möchte.

Vielen Dank!
Kuddeldaddeldu