Tim Tepaße: (Prototype) AJAX ResponseText und JSON

Beitrag lesen

Hallo,

es wäre schön, wenn Du nebenbei bemerken würdest, dass Du Prototypes Ajax-Objekte statt normalen XMLHttpRequest benutzt, dann verwirrst Du den armen Timo und andere nicht so und ersparst diesen die dummen Nachfragen und das Nichtbenutzen von Google. ;)

var response = new Ajax.PeriodicalUpdater(
     'ziel',
     'execute.php',
                   {
         method: 'post',
parameters: 'i=' + document.hier.versteckt.value,
frequency: 2,
                       onSuccess: function() {
                           var antwort = response.responseText.evalJSON();;

Du solltest ab besten nicht mit dem Ajax.PeriodicalUpdater-Objekt arbeiten, sondern das Response-Objekt nutzen, was bei allen Callback-Funktionen mitgeliefert wird. Ajax.PeriodicalUpdater ist ein erweitertes Ajax.Updater, welches ein erweitertes Ajax.Request ist. Somit gilt für den PeriodicalUpdater die gleichen Zugriffsvarianten wie für den Request. Unter anderem auch die, dass den Callbacks-Funktionen als erstes Argument ein Ajax.Response-Objekt geliefert kriegen, wenn sie aufgerufen werden. Sprich, Du schreibst das hier:

~~~javascript var updater = new Ajax.PeriodicalUpdater("ziel", "execute.php", {
                        method : "post",
                        onSuccess : function (response) {
                            var text = response.responseText.evalJSON()
                            // ...
                        }
                    });

  
Um es noch mal zu wiederholen: Die Response wird an die Callback-Funktion onSuccess übergeben. Du dagegen greifst in Deiner Callback-Funktion auf das Ajax.PeriodicalUpdater-Objekt zu, dass Du in der globalen Variable response gespeichert hast. Dass dieses Objekt kein Attribut namens responseText hat und deswegen beim Zugriff auf Ajax.PeriodicalUpdater.resonseText immer undefined rauskommen muss, ist dann klar.  
  
  
Tatsächlich kann man Dein Zeugs mit diversen Features von Prototype noch erweitern und damit besser machen. Du kannst z.B. JSON automatisch evaluieren lassen, wie Du im [Prototype AJAX Tutorial](http://prototypejs.org/learn/introduction-to-ajax) nachlesen kannst:  
  
  ~~~javascript
new Ajax.PeriodicalUpdater("ziel", "execute.php", {  
      onSuccess : function (response) {  
          tueWasMit(response.responseJSON);  
      }  
  });

Das zweite Argument für die Callback-Funktion existiert dann, wenn Du vom Server aus den für JSON richtigen MIME-Type, nämlich "application/json" mitschickst; schließlich verschickst Du ja JSON und nicht "text/html". In PHP kannst Du das meines Wissens mit dem Aufruf von [link:http://de.php.net/manual/de/function.header.php@title=header]('Content-type: application/json'); bevor Dein Skript irgendwelchen Code sendet. Bei kurzen JSON-Strukturen könnte man diese sogar in einem X-JSON-Header tun und Prototype reagiert auch darauf. Für mehr dazu und zu den Bedingungen des evaulierens, guck Dir mal die möglichen Optionen für Prototype-AJAX-Aufrufe an.

parameters: 'i=' + document.hier.versteckt.value,

Diese Zuweisung hier könnte darunter leiden, dass im Feld "versteckt" irgendwelche Werte stehen, die nicht richtig URL-kodiert sind. Prototype erwartet jedoch einen URL-kodierten String; wenn der falsch ist, ist die zusammengebastelte URL hinterher falsch. Aber Prototype nimmt dort auch gerne ein Objekt und bastelt daraus einen URL-kodierten String. Wenn Dein Framework das für Dich macht, sollte man es nutzen; meistens haben diese nämlich die Fehler, die man selber gemacht hat, schon hinter sich gelassen. Das sähe dann verkürzt so aus:

~~~javascript new Ajax.PeriodicalUpdater("ziel", "execute.php", {
          parameters : { "i" : [link:http://prototypejs.org/api/utility/dollar-f@title=$F("versteckt")] }
      }
  });

  
Dir fällt bestimmmt auf, dass ich hier öfters auf Tippfaulheit den PeriodicalUpdater nicht in einer Variablen sichere im Gegensatz zu Deiner obigen irrigen response-Variable. Das geht, ist aber nicht so toller Stil. Besonders beim PeriodicalUpdater will man später auf den laufenden Updater zugreifen und eventuell dessen stop()-Methode aufrufen. Nur so nebenbei bemerkt.  
  
  

> feld1.innerHTML =  antwort.nachname;  
> feld2.innerHTML = 'aktualisiert: ' + Date();  
  
In Deinem Skript hast Du nirgends die Variablen feld1 und feld2 definiert. Wenn Du auf die divs anhand ihrer ID zugreifen willst, gibt es doch klassisches documentGetElementById() bzw in Prototype die Funktion [$(id)](http://prototypejs.org/api/utility/dollar), die die Elemente auch zu Prototype-Elementen upgraded:  
  
  ~~~javascript
$("feld1").replace(antwort.nachname);  
  $("feld2").replace("Aktualisiert: "  Date());

Zwei Gedanken noch:

• PeriodicalUpdater ist wie sein Cousin Updater eigentlich dafür da, die ganze Response direkt in ein Element im Dokument einzuhängen. Derzeit scheinst Du das ja mit div#ziel zu machen; langfristig scheint es Dir lieber zu sein, wohl nur die Einzelfelder zu benutzen. Eventuell wäre es dann sinniger, mit dem PeriodicalExecuter in regelmäßigen Abständen jeweils ein Ajax.Request-Objekt loszujagen, anstatt, dass der Ajax.PeriodicalUpdater sich dann auf die Suche nach einem von Dir nicht gewünschtem Element macht.

• Äh. Ich bin kein PHP-Mensch, aber wenn ich Dein Skript so querlese, dann macht das einen Datenbankquery, nimmt davon den ersten Datensatz, ver-JSON-t und verschickt diesen. Und dann ist das Ende des Skriptes. Wenn dann zwei Sekunden später ein neuer Request kommt, wird das Skript neu gestartet, der Query neu gestellt und wieder nur der erste Datensatz geholt, weil die alte Datenbankverbindung beim Beenden des alten Skript-Aufrufes verschwunden ist. Für einen Liveticker fehlt da wohl das „live“, es sei denn Deine Vorstellung von „live“ ist es, immer den ersten Datensatz darzustellen. Aber vielleicht habe ich auch missverstanden, was Du da machen willst. Und Du solltest Dir auch mal mysql-real-escape-string() angucken, wenn Du nicht willst, dass da jemand über den Parameter i irgendwelche bösen SQL-Befehle einschmuggelt. Ich hab von PHP keine große Ahnung, aber wenn Dein datenbank.inc.php dieses PearDB ist, solltest Du dort mal in der Dokumentation gucken. Da scheint eine Möglichkeit zu geben, in SQL-Queries Platzhalter zu benutzen, die dann mittels Array befüllt und hoffentlich dabei maskiert und damit vor SQL Injection geschützt werden.

Tim