Rezeptsuche mit AJAX Autocomplete 2: das Javascript und die PHP-Datei

Das Javascript

Wir haben ja im vorigen Beitrag unsere Javascriptdatei rezepte_suche.js geladen, jetzt stelle ich sie hier mal in aller Kürze vor. Die ist nicht auf meinem Mist gewachsen, das ist eine Standardprozedur für einen AJAX-Call die ich mir zusammengegooglet und nach meinen Bedürfnissen angepaßt habe. Sie enthält genau eine Funktion, nämlich die rezepte_suche mit dem Parameter inhalt, in dem steckt der vom Benutzer eingegebene Inhalt des Textfeldes aus dem Formular:

function rezepte_suche(inhalt)
{
 if (inhalt=="")
 {
  return;
 }
 if (window.XMLHttpRequest)
 {
  // AJAX nutzen mit IE7+, Chrome, Firefox, Safari, Opera
  xmlhttp=new XMLHttpRequest();
 }
 else
 {
  // AJAX mit IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
 }
 xmlhttp.onreadystatechange=function()
 {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
  {
   
   document.getElementById("liste").innerHTML=xmlhttp.responseText;
  }
 }
 xmlhttp.open("GET","http://localhost/drumenus/sites/all/modules/autocom/rezeptesuche.php?q="+inhalt,true);

 xmlhttp.send();
}

Was passiert hier? Zuerst wird abgefragt, ob inhalt leer ist und in dem Fall nur ein return ausgelöst.

Wenn inhalt nicht leer ist, greifen zwei IF-Abfragen, die Browserabhängig die Variable xmlhttp unterschiedlich belegen. Wir schauen mal nur den ersten Zweig an:

xmlhttp=new XMLHttpRequest();

Hier wird ein neues Objekt vom Typ XMLHttpRequest angelegt, das wird im Folgenden weiterverarbeitet. Wer dazu Genaueres wissen möchte dem sei diese Seite der wikibooks empfohlen.

Wenn sich am Status des Formularfeldes etwas ändert, feuert folgende Funktion:

xmlhttp.onreadystatechange=function()
 {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
  {
   
   document.getElementById("liste").innerHTML=xmlhttp.responseText;
  }
 }

Die div mit der id liste kriegt einen neuen Inhalt, nämlich den Rückgabewert des Requests. Wir der aussieht, wird in unserer PHP-Datei geregelt, dazu gleich mehr.

Wichtig ist jetzt noch der open-Aufruf:

xmlhttp.open("GET","http://localhost/drumenus/sites/all/modules/autocom/rezeptesuche.php?q="+inhalt,true);

Ich hab hier den Pfad zur PHP-Datei noch fest verdrahtet, das läßt sich sicher auch eleganter lösen, aber für Testzwecke tuts das. Die PHP-Datei kriegt als Parameter unseren inhalt mit, das ist immer noch der Inhalt des Formularfeldes so wie ihn der Benutzer eingegeben hat. Fehlt nur noch der Auslöser:

xmlhttp.send();

Und Schuß! Das setzt den Request ab.

Die aufgrufene PHP-Datei

Die benimmt sich nicht anders, als wenn sie von einem Formular aus aufgerufen würde, und sie übernimmt den Parameter inhalt in der Variablen q. Ansonsten ist sie recht übersichtlich:

<?php

$rezept = '';
if ( isset($_GET['q']) )
{
  $rezept = $_GET['q'];
}

$pdo = new PDO('mysql:host=localhost;dbname=drumenus', '*****', '*****');

//Suche nach enthaltenem String %suchstring%
$sql = "SELECT * FROM node where title like '%".$rezept."%' and type like 'rezept' order by title";
$records = $pdo->query($sql);

foreach ($records as $row) {
        
        echo "<option>".$row['title']." #".$row['nid']."</option><br>";
        
    }
?>

Ich hole mir erstmal den Inhalt von q auf die Variable $rezept. Dann verbinde ich mich mit der Drupal-Datenbank und hole mir aus der node-Tabelle mit dem Select alle Datensätze der Rezepte (type like ‚rezept‘), die den Inhalt von $rezept im Titel enthalten. Innerhalb der Foreach-Schleife wirds dann nochmal interessant, ich klemme vor und nach dem Titel des Rezeptes die <option>-Tags dran, die brauchen wir nachher im Formular für die Datalist. Ausserdem nehme ich noch die nid mit, die brauchen wir dann für die Ausgabe des Rezeptes. Das wars dann aber auch schon.

Das Formular ist jetzt scharfgeschaltet

Wenn der Benutzer jetzt zum Beispiel salat in das Textfeld eingibt, erhält er eine Liste aller Rezepttitel, in denen der String salat vorkommt:

salat
salat

Jetzt muss nur noch etwas passieren, wenn er einen der Einträge auswählt und auf Return drückt. Ich hab das so gelöst: in der autocom.module kommt nach dem Formular noch folgender Code:

if (isset($_POST['ausgesucht'])){
    
    echo "Vielen Dank! Ihre Auswahl: <h2>".$_POST['ausgesucht']."</h2><br>";

    $text = strstr($_POST['ausgesucht'], '#');
    $text=substr($text,1); 
    
    $options = array('absolute' => TRUE);
    $nid = $text; // Node ID
    $url = url('node/' . $nid, $options);
    
    echo "<h2><a href = ".$url.">Link zum Rezept</a></h2>";

    } //ende von if isset

Wenn der Benutzer einen Eintrag ausgewählt hat (If (isset…)), zerlege ich mir die Auswahl und hole mir nur die nid nach dem #. Zu der wiederum hole ich mir die URL des betreffenden Nodes, und gebe damit einen Link zum Rezept aus. Das wars! Aussehen tut das Ganze so:

link_zum_rezept
link_zum_rezept

Ich hab hier jetzt mal mit dem Link gearbeitet, man könnte hier natürlich auch mit der nid in die Tabelle field_data_body gehen und sich den body_value ausgeben lassen, das wäre der komplette Text des ausgewählten Rezeptes, aber das ist reine Geschmackssache.

Drupal-Puristen werden mich jetzt wahrscheinlich steinigen, weil man „das so nicht machen kann“, aber der Autocomplete funktioniert jedenfalls ohne allzu grossen Aufwand. Es gibt sicher hier und da noch ein paar Optimierungspotentiale, was man unbedingt noch angehen sollte wäre der fest verdrahtete Pfad zu der PHP-Datei in der rezepte_suche.js, das ist sicher nicht so besonders gut gelöst, aber für Demozwecke tuts das, finde ich. mir hats Spaß gemacht, und das Ergebnis ist ganz ansehnlich.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert