Der Interaktionsdesigner – PHP, jQuery und CSS

4. Januar 2009 (08:00 Uhr)

Asynchrone Datenübertragung zwischen TYPO3 und jQuery

TYPO3 Entwicklung und Liebe

Nach dem ich mal wieder über den Appell an Webentwickler gestolpert bin, beginne ich meinen ersten zweiten Eintrag dieses Jahres mit einem tollen Thema welches ich zwischen den Jahren entdeckt habe: Die effektive Kommunikation zwischen TYPO3 und jQuery dank Ajax.

Möglich macht das die Funktionalität der eID seit TYPO3 Version 4 und die geniale Handhabung vom Lieblingsframework mit JSON. Eingesetzt hab ich es in einer tollen, neuen Extension die wir entwickelt haben und die hoffentlich bald das Licht der Welt erblicken wird. Das wird dann gesondert gefeiert.

Um was geht es?

Die Eingaben eines Benutzers werden asynchron, d.h. ohne die Seite neuzuladen, an den Server übergeben. Der verarbeitet sie und liefert ein Ergebnis zurück, welches von jQuery verarbeitet und dargestellt wird.

Gebraucht wird diese Technik um zum Beispiel registrierte Benutzer anzuzeigen. Ähnliches habe ich schon beschrieben im Beitrag über das nachladen kompletter Seiteninhalte. Dort wurde ein neuer Seitentyp angelegt. Das hat allerdings den Nachteil das die ganze Seite gerendert werden muss. Wir können schon wesentlich früher den Renderingprozess abbrechen und zügig ein Ergebnis bekommen.

Vorbereitungen mit TYPO3

Als erstes bereiten wir TYPO3 darauf vor und erstellen eine neue Extension mit dem Kickstarter. Ich habe ein Frontend Plugin erstellt und die üblichen Spracheinstellungen gewählt. Was man will ist also schnell zusammen geklickt.

Und jetzt wirds spannend: In der ext_localconf.php registrieren wir die eID (das e steht für Extension):

$TYPO3_CONF_VARS['FE']['eID_include']['MEINE_eID'] = 'EXT:kiwi_database/pi1/MEINE_eId.php';

Es geht um das Frontend, eine neue eID wird eingebunden, für die eben erstellte Erweiterung. MEINE_eID ist durch einen guten Namen zu ersetzen (Extensionkey vielleicht).
Im Wert der Variable ist der Pfad zum Script angegeben welches benutzt wird. EXT: zeigt auf den Ordner in dem die Extensions gespeichert sind, dann weiter zu unserer Erweiterung und zur speziellen Datei.

Ist diese Datei angelegt, einfach mal ein <? echo "Hallo Welt"; ?> darin speichern und zum Testen aufrufen, über den neuen Parameter eID: www.mein-typo3-projekt.de/index.php?eID=MEINE_eID. Wenn das auf eine weiße (super schnelle) Seite weiterleitet auf dem die Welt begrüßt wird, hat alles geklappt.

Wenn nicht, dann lohnt sich ein Blick ins Error Log von PHP und einfach weiter probieren (viel Glück).

Drei Dinge sind für die Datei MEINE_eId.php wichtig:

1. Sicherheit

if (!defined ('PATH_typo3conf')) die ('Could not access this script directly!');

Mit dieser Zeile wird der direkte Aufruf der Datei verhindert. Sicher ist sicher.

2. Datenbankzugriff

$feUserObj = tslib_eidtools::initFeUser(); // Initialize FE user object
tslib_eidtools::connectDB(); //Connect to database

Mit diesen zwei Befehlen steht die Datenbankverbindung wir gewohnt im globalen Array $GLOBALS["TYPO3_DB"]; zur Verfügung. Es ist sehr einfach zu testen ob es funktioniert hat:
echo "<pre>", print_r($GLOBALS["TYPO3_DB"]), "</pre>";

Diese Zeile gibt nicht nur aus, ob eine Verbindung besteht, sondern auch den zuletzt ausgeführten MySQL Query. Sehr praktisch ;)

3. Die eigene Extension

Und damit kommen wir zu einer Einschränkungen. Es gibt kein cObj, da keine Seite aufgebaut wurde. Man kann zwar, ähnlich der Datenbank eins erstellen, aber das ist nicht nur kompliziert sondern hebt den Grund der Extension auf, da dann wieder eine komplette Seite gerendert wird. Das zur Folge das es nicht möglich ist die Benutzereinstellungen im Typoscript abzufragen. Ich empfehle die Auslagerung in die localconf.php.

require_once('typo3conf/ext/meine_ext/pi1/class.tx_meineext_pi1.php');
$obj = t3lib_div::makeInstance("tx_meineext_pi1");

Die erste Zeile bindet die passende Datei ein, die zweite erschafft eine neue Instanz der eigenen Extension.

Langsam Richtung JSON

In der Extension wird jetzt abgefragt, was abgefragt werden muss. Zugriff auf in der URL übergebenen Parameter erhählt man z.B. über $GLOBALS["_GET"]["PARAMETER_NAME"].

Am Ende sollte ein Array zur Verfügung stehen, welches alle Daten beinhaltet. Das wird in JSON umgewandelt:

$response = $obj->getAnswer($GLOBALS["_GET"]);
echo json_encode($response);

Fertig, auf zum Frontend

page.includeJS.file1 = fileadmin/template/js/jQuery.js
page.includeJS.file2 = fileadmin/template/js/jquery.meineext.js

Interessant ist die zweite Datei. Wie gewohnt wird alles in den jQuery-Aufruf verpackt, der wartet bis das DOM geladen ist. Wie ein HTML Formular aussieht weiß vermutlich jeder. Nehmen wir an das Form-Tag trägt die ID assi (für asynchron) und beinhaltet genau ein Textfeld für die Eingabe. Das Javascript muss das Abschicken des Formulars abfangen, versenden, die Antwort als JSON Objekt verarbeiten und anzeigen. Klingt kompliziert? Aber nicht mit jQuery:

$(document).ready(function() {
	// Das Abschicken des Formulars verhindern
	$("#assi").submit(function() {

		//Ajaxabfrage stellen
		$.ajax({
			url: "index.php",		// Achtung mit RealURL!
			type: "GET",			// Daten per GET verschicken
			data: {
				eID: "MEINE_eID",	// die erstellte eID
				input: $("#assi input[type=text]")	// Benutzereingabe
			},
			dataType: "json",		// das gibts zurück

			// Es hat funktioniert?
			success: function(response) {
				// Code der ausgeführt wenns geklappt hat
				// !! Wesentliches Ding !!
			},

			// Schade, es war ein Fehler
			error: function(error) {
				alert("Sorry, hat nicht funktioniert");
			}
		});

		//Damit das Formular nicht doch noch abgeschickt wird
		return false;
	});
});

Ich mag jQuery Code! Nach einiger Zeit hat man sich an die wilden Klammern gewöhnt und kann nicht mehr damit aufhören. Die Kommentare erläutern die einzelnen Dinge, oder die offizielle Doku, wir wenden uns lieber dem wesentlichen Ding zu!

Verarbeitung von JSON Objekten zu HTML mit jQuery

Damit die Funktionen besser nachvollzogen werden können, ein Beispiel: So sieht die Funktion getAnswer() vereinfacht aus:

function getAnswer() {
	$a = Array(
		0 => Array("name" => "paul", "like" => "Webstandards"),
		1 => Array("name" => "ramon", "like" => "Bier"),
		2 => Array("name" => "max", "like" => "Sport")
	);
	return $a;
}

Das wird als JSON Objekt sowas:

[{"name":"paul","like":"Webstandards"},{"name":"ramon","like":"Bier"},{"name":"max","like":"Sport"}]

Im wesentlichen Teil der jQuery Ajaxabfrage steht dieser String jetzt als Objekt zur Verfügung. Testen lässt sich das über die Firebug Konsole mit console.log(response). Das und alles folgende spielt sich in der Funktion success(response) ab!

Jedes Array verfügt über die Eigenschaft length, es lässt sich also herausfinden wieviele Elemente vorhanden sind.

if(response.length > 0) {
}

Das else überlasse ich mal jedem selbst, kommen wir zur Superfunktion $.each(). Diese erwartet zwei Parameter: Das zu untersuchende Objekt (response) und eine Funktion die auf jede Zeile angewendet werden soll.

Angenommen es gibt auf der Seite eine Liste (<ul>) mit der ID answer, dann wird diese mit neuen Listenelementen versorgt:

var new_content = "";
$.each(response, function(i, row) {
	new_content+= "<li><strong>"+row.name+"</strong> mag "+row.like+"!</li>";
});
$("#answer").html(new_content);

Die Funktion, welche auf jede Zeile angewendet wird, erwartet zwei Parameter: i ist der Indikator welcher die aktuelle Position beinhaltet, row ist das aktuelle Objekt. Die Schlüssel aus dem PHP Array sind hier die Namen der Eigenschaften, herrlich oder?

Fertig!

Um die Besucher ohne JavaScript nicht außen vor zu lassen muss noch sichergestellt werden, dass die Extension bei "normal" erhalten der Daten die gleiche Ausgabe erzeugt. Das dürfte bekannt sein?!

Um sich den Stress mit einem Template zu sparen gibt es dann in ein paar Tagen irgendwann meine neue Extension! Bis dahin wünsche ich erfolgreiches Programmieren in 09!

Chris 24. Juni 2009 (10:12 Uhr)

Hallo,
das ist ein ausgesprochen gutes Tutorial, Kompliment!!
Das einzige was ich noch erwähnen würde, das man nach dem Konfigurieren der ext_localconf und dem einsetzen des eigenen Scriptes (Vorbereitung mit Typo3) im Backend den Cache löschen sollte, bevor man in den Error Log schaut. … erspart viel Arbeit :) .

Grüße

Paul 30. Juli 2009 (20:36 Uhr)

Cache löschen ist sehr wichtig!!!

Außerdem muss man beachten, dass der Parameter wirklich mit zwei Großbuchstaben geschrieben wird:

index.php?eID=meine_ext

Erspart auch viel arbeit ;)

Michael 21. November 2009 (08:58 Uhr)

Kleiner fehler:

FALSCH: [{"name":"paul","like":"Webstandards"},{"ramon":"ramon","like":"Bier"},{"name":"max","like":"Sport"}]

RICHTIG: [{"name":"paul","like":"Webstandards"},{"name":"ramon","like":"Bier"},{"name":"max","like":"Sport"}]

Paul 21. November 2009 (15:53 Uhr)

Danke Michael, du hast vollkommen recht. Ist korrigiert.

Jayden 5. Januar 2010 (14:23 Uhr)

Hi, finde das Tutorial eigentlich auch ganz gut und versuche gerade das umzusetzen, allerdings würde ich gerne POST verwenden. Wie würde denn ein html-Link aussehen, der die JQUERY-Funktion aufruft und die Argumente übergeibt?

Cheers, Jayden

Lina Wolf,
Marit AG
4. März 2010 (10:52 Uhr)

Hi Paul,
Vielen Dank für da tolle Tutorium. Allerdings funktioniert die Parameterübergabe so leider nicht, sondern es müsste heißen:
data: {
eID: “MEINE_eID”, // die erstellte eID
input: $(”#assi input[type=text]“).attr(’value’) // Benutzereingabe
},
Da data Strings und keine Objekte als Eingabe erwartet muss man das entsprechende Attribut hier auslesen.
Außerdem sollten Abfrage von GET- und POST-Paramtern für größtmögliche Unabhängigkeit von Webserverkonfigurationen grundsätzlich nur über die entsprechenden TYPO3-API Funktionen, z.B. mit t3lib_div::_GET() oder t3lib_div:_GP($var) erfolgen. Dies Funktioniert auch im Zusammenhang mit der eID einwandfrei 

Zum Aufruf aus HTML heraus bleibt noch zu sagen, dass man im Fall von Ajax nicht aus JQuery heraus verhindern kann, dass das Formular abgesendet wird. Hier ein Beispiel, wie das Formular aussehen müsste:

Wichtig ist das onsubmit=”return false”. Es verhindert ein frühzeitiges absenden des Formulars bevor eine Ajax Antwort kam.
Liebe Grüße aus München – Lina

Ajax unter
TYPO3? eID
machts einfach!
| Jim Superfly
18. April 2010 (21:00 Uhr)

[...] Ajax Forms with jQuery Asynchrone Datenübertragung zwischen TYPO3 und jQuery [...]

Stefan 11. Mai 2010 (08:04 Uhr)

Hallo, ich habe mal ne Frage zu dem Tutorial, denn ich stehe gerade vor nem Problem und wollte mal fragen ob man das hiermit realisieren kann? Ich habe zur Zeit auch eine Vorschlagsfunktion in meinem Skript integriert. Allerdings binde ich es in meiner Extension durch eine Javascrtipt Datei ein, aus der JS Datei wird dann auf eine PHP Datei zugegriffen in der sich die Datenbankabfrage befindet. Das ist so natürlich nicht gut, denn mir stehen die Typo3 eigenen Datenbankabfragen nicht zu Verfügung. Habt ihr ne Idee wie ich das am BEsten machen könnte. Ich wäre so dankbar. So ist es zur Zeit:

In meiner Extension integriere ich das Javascript:

Da drinne wird der Inhalt aus dem Eingabefeld an die PHP Datei übergeben und die Abfarge gemacht:

var s1 = new Autocomplete(”tx_aasregister_pi1[searchWordSubCategories]“, function() {

this.setValue = function( id ) {
document.getElementsByName(”staffID”)[0].value = id;
}

// If the user modified the text but doesn’t select any new item, then clean the hidden value.
if ( this.isModified )
this.setValue(”");

// return ; will abort current request, mainly used for validation.
// For example: require at least 1 char if this request is not fired by search icon click
if ( this.value.length < 1 && this.isNotClick )
return ;

// Replace .html to .php to get dynamic results.
// .html is just a sample for you
return "typo3conf/ext/aas_register/pi1/vorschlag/ausgabe_produkt_dienstleistung.php?q=" + this.value;
// return "completeEmpName.php?q=" + this.value;
});

Nur wie kann ich das nun mit Jquery und Typo3 machen? Bitte helft mir! Danke

Paul 15. Mai 2010 (15:36 Uhr)

Hallo, vielen Dank für die Kommentare! Lina, du hast vollkommen Recht mit deinen Anmerkungen. Eine Alternative zu return false; ist auch die Funktion preventDefault() die im Eventobjekt vorhanden ist. Die kann man auch am Anfang aufrufen:

$('form').submit(function(e) {
e.preventDefault();
// ... weiterer code

Stefan, anstatt eines eigenen PHP Scripts solltest du eine TYPO3 Extension erstellen. Mit dem Kickstarter ist das relativ easy. In der stehen dir dann auch alle TYPO3 Datenbankschnittstellen zur Verfügung!

Und Jayden, du hast es inzwischen sicher schon selbst heraus gefunden. In der Ajaxfunktion von jQuery kannst du mit type: “POST” eine Postabfrage starten. Nichts leichter als das :)

Schöne Grüße, Paul

martin 19. Mai 2010 (15:31 Uhr)

hallo paul,
super tutorial, damit hab ich endlich meine erste ajaxbridge zu typo3 gebaut!
danke dir!
martin

Einen Kommentar schreiben

(wird nicht veröffentlicht)

(wird veröffentlicht!)