If this tutorial is helpful to you, you can donate some money to the tutorial author via Paypal.

Dieses Tutorial soll euch eine kleine Einführung geben, wie man AJAX zusammen mit TYPO3 am besten nutzen kann! Dazu werden wir das Javascript Framework jQuery verwenden. Selbstverständlich kann man auch jedes andere Framework verwenden was eine AJAX API anbietet. Grundlegend gibt es bei TYPO3 zwei verschiedene Wege im Frontend und einen im Backend über die man einen AJAX Request absetzen kann. Da wäre im Frontend einmal der so genannte typeNum, wo man per GET Parameter den entsprechenen type mit übermittelt, und zum anderen gibt es den sogenannten eID Mechanismus. Ich werde zu beiden Wegen ein kleines Beispiel zeigen. Im Backend gibt es den Weg über die ajaxID. Dazu werde ich ganz zum Schluß noch ein paar Worte sagen! Beginnen wir aber erst mit dem Frontend und mit den Grundlagen die beide Wege die ich genannt hatte benötigen. Bedeutet, wir müssen erst einmal das jQuery Framework einbinden um eine entsprechende AJAX API nutzen zu können. Hierzu verwende ich immer folgendes Script:

jQuerySrc = 'fileadmin/js/jquery-min.js';

// only load jQuery if not present
if (typeof jQuery == 'undefined')  {
    document.write("
<script type="text/javascript" src="\&quot;http:/ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js\&quot;"></"+"script>");
}

// if Google is down
if (typeof jQuery == 'undefined') {
    document.write("<script type=\"text/javascript\" src=\"" + jQuerySrc + "\"></"+"script>");
}

Was passiert hier:


Es wird überprüft ob jQuery schon eingebunden wurde. Es kann ja sein das per TypoScript oder einer anderen Extension das jQuery Framework schon in die Seite eingebunden ist und doppelt wollen wir es ja nicht haben. Wenn jQuery also noch nicht eingebunden wurde wird es von der Google API geholt. Sollte die Google API einmal down sein, was zu 99,99% nie der fall sein sollte, überprüft eine weitere Bedingung erneut ob jQuery eingebunden wurde. Ist die Google API also mal down, lachen wir google erstmal kurz aus und lehnen uns wieder entspannt zurück, den es wird dann unsere lokale Version eingebunden. Ihr müsst dazu natürlich die jQuerySrc Variable entsprechend anpassen. Soweit so gut, Grundstein ist gelegt, für Kaffee ist gesorgt, oder ? :-) Weiter gehts... In unserem Beispiel gehen wir davon aus das ein Klick auf einen Button, der die id "triggerButton" als Attribut hat, den AJAX Request auslöst (der sogenannte Trigger - Auslöser). In jQuery kann das so aussehen:

$('#triggerButton').bind('click', function() {
    // mache was
});

Sehr gut, Putzlappen raus, jetzt kommt AJAX zum Einsatz :-) Innerhalb des click Events kommt jetzt unser AJAX Request rein der wie folgt aussehen kann

$.ajax({
    url: '',
    success: function(data) {

    },
    error: function(XMLHttpRequest, textStatus, errorThrown) {

    }
});

Das ist ein Aufruf mit grundlegenden Einstellungen, hier gibt es natürlich noch weitere Einstellungen um den Rückgabetyp zu definieren und und und, hier einfach mal in die AJAX API von jQuery schauen. Die "url" erkläre ich gleich da hier die zwei unterschiedlichen Wege zum Einsatz kommen. "success" wird aufgerufen wenn der Call erfolgreich war und "error" sofern ein Fehler aufgetreten ist! Beides sind funktionen in denen man dann entsprechende Aktionen auslösen kann! Ok, fangen wir mit dem ersten Weg an:

Der typeNum!


Der typeNum sollte uns schon etwas sagen, den unsere Webseite basiert auf dem typeNum 0. 0 Ist dabei der default typeNum. Gibt der user also die Domain euerer Webseite ein und gibt keinen "type" als GET Parameter ein, wird der default typeNum 0 genommen. Das TypoScript sieht in den meisten Fällen so aus

page = PAGE
page.typeNum = 0
page.bodyTag =page.10 = TEMPLATE page.10.template = FILE page.10.template.file = fileadmin/index.html page.10.workOnSubpart = DOCUMENT page.10 { subparts { CONTENT < styles.content.get } # usw }

Ok, also, wir können also beliebig viele weitere typeNums definieren, diese müssen halt nur einmalig sein, da der letzte sonst immer gewinnen würde. Ihr kennt das Prinzip, TypoScript wird von oben nach unten eingelesen und wenn ihr Definitionen doppelt drin habt gewinnt immer der letzte! Wunderbar, wir wollen also einen typNum definieren den wir für unsere AJAX Anfrage nutzen. Also, tragen wir folgendes im TypoScript Setup ein:

ajaxCall = PAGE
ajaxCall {
  typeNum = 5000
  10 < plugin.tx_unsereextension_pi1

  config {
    disableAllHeaderCode = 1
    xhtml_cleaning = 0
    admPanel = 0
    debug = 0
    no_cache = 1
  }
}

[Setzt voraus wir haben eine Extension "unsereextension" die installiert ist. Das kann eine recht einfache über den Kickstarter erstellte Extension sein die mindestens eine pi1 enthält] Das TypoScript bewirkt das, wenn wir eine URL mit dem type=5000 aufrufen, das sofort an das Plugin tx_unsereextension_pi1 weitergeleitet wird und das was dort als return zurück kommt ausgegeben wird. Im Bereich config stellen wir noch ein paar Feinheiten ein, wie zB disableAllHeaderCode = 1 was bewirkt das wir unser Ergebnis als reinen Plaintext wieder bekommen ohne das der von TYPO3 generierte HTML Header etc. mit ausgegeben wird. Da wir auch keine anderen Ausgaben haben wollen deaktivieren wir auch das adminPanel und die debug Ausgabe und deaktivieren das Caching. In unserer Extension steht aktuell folgendes in der main Methode typo3conf/ext/unsereextension/pi1/class.tx_unsereextension_pi1.php

// ...

public function main($content, $conf) {
    return 'Das ist ein Test!';
} 

// ...

Um vorab einmal zu testen ob unser neu angelegter typeNum funktioniert rufen wir das ganze manuell auf. Gebt also euere Domain + den neuen type als GET Parameter an: http://www.domain.de/?type=5000 Als Ausgabe müssten wir jetzt sehen "Das ist ein Test!" und wenn wir in den Quellcode der Seite gucken dürfte dort auch KEIN HTML Tag etc. stehen sondern nur der reine Plaintext. Sollte das nicht funktieren stellt bitte sicher ob ihr den Frontend Cache geleert habt :-) Ein häufiger Fehler wenn man nicht mit dem Template Modul arbeitet. Im Template Modul passiert das nämlich automatisch. Aber wir gehen davon aus das alles geklappt hat und kümmern uns jetzt um das AJAX Im AJAX Call tragen wir also in der "url" folgendes ein

$.ajax({
    url: '/?type=5000',
    success: function(result) {
        alert(result);
    },
});

Wenn jetzt auf den Button geklickt wird den wir als Trigger nutzen, müsste ein Alert erscheinen in dem steht: Das ist ein Test! Ich würde sagen, glückwunsch! Ihr habt es geschafft! Jetzt könnt Ihr mit jQuery das Ergebnis entsprechend verarbeiten. Dem AJAX Call kann man natürlich auch noch Daten mit übergeben damit, anhand dieser Daten kann man im AJAX Script bestimmte Aktionen durchgeführen lassen! Nehmen wir also an ihr wollt die FE User ID eines eingeloggten Users mit übergeben

var useruid = 1; // müsste dann dynamisch gefüllt werden

$.ajax({
    url: '/?type=5000',
    data: 'useruid=' + useruid,
    success: function(result) {
        alert(result);
    },
});

Der Aufruf sieht jetzt aber wie folgt aus: http://www.domain.de/?type=5000&useruid=X Dementsprechend könnt ihr in euerem AJAX Script auf den GET Parameter zugreifen! Möchte man die Extension mit mehreren verschiedenen typNums nutzen kann man in der Extension einfach folgendes machen

switch ($GLOBALS['TSFE']->type) {
  case 5000: // fuer typeNum 5000
    break;
  case 5001: // fuer typeNum 5001
    break;
  // usw
}

Der Vorteil bei dem Weg über typeNum ist das uns alle globalen Variablen wie das komplette TSFE mit cObj etc. zur Verfügung stehen. Bei dem Weg per eID musste man vor der TYPO3 Version 4.3 noch ein eigenes TSFE Objekt erzeugen. Seit der 4.3 bietet das das eID Script aber an womit wir direkt zum zweiten Weg kommen!

eID steht für Extension ID


Der eID Mechanismus ist seit der Version 4.0 dabei! Angesprochen wird er über einen GET oder POST Parameter. Sobald also eID als Parameter in der URL vorhanden ist, zB. www.domain.de/?eID=schuesselwort, wird der normale Prozess sehr früh abgebrochen und auf ein Script weitergeleitet was von uns vorher registriert wurde. Da der normale Prozess so früh abgebrochen wird kommt es auch noch zu keiner Ausgabe. Es wird nichts gecachet und kein HeaderCode etc. generiert. Wir bekommen also ein blankes Ergebnis unserer main Methode ausgegeben. Wollen wir uns einmal die index_ts.php (typo3/sysext/cms/tslib/) Zeile 174 bis 185 ansehen.

// *********************
// Look for extension ID which will launch alternative output engine
// *********************
if ($temp_extId = t3lib_div::_GP('eID')) {
    if ($classPath = t3lib_div::getFileAbsFileName($TYPO3_CONF_VARS['FE']['eID_include'][$temp_extId])) {
        // Remove any output produced until now
        ob_clean();
        require($classPath);
    }
    exit;
}

Hier wird überprüft ob es einen GET bzw POST Parameter mit dem Namen eID gibt, sofern vorhanden wird geguckt ob dieser Key registriert wurde und der Pfad zu unserem Script wird in $classPath gespeichert und per require eingebunden. Danach folgt ein exit damit der restliche Prozess von TYPO3 nicht mehr ausgeführt wird. Wie genau können wir unser Script registrieren ? Das sagen wir dem System über $TYPO3_CONF_VARS['FE']['eID_include'][$temp_extId] Wir müssten entweder in die localconf.php oder in eine ext_localconf.php einer Extension folgendes Eintragen

$TYPO3_CONF_VARS['FE']['eID_include']['helloworld'] = 'EXT:meinExtKey/meinScript.php';

Steht jetzt also in der Adresse www.domain.de/?eID=helloworld geht er in die erste if Abfrage und sieht das $TYPO3_CONF_VARS['FE']['eID_include'][$temp_extId] vorhanden ist und speichert 'EXT:meinExtKey/meinScript.php' in die Variable $classPath und includiert unser Script. Da unser Script noch leer ist bekommen wir eine weiße Seite angezeigt in der auch der komplette Quelltext leer ist. Damit wir auch ein FE User Objekt, das TSFE Objekt und eine Datenbank Verbindung zur Verfügung haben, geben wir folgendes ein

$feUserObject = tslib_eidtools::initFeUser();
$TSFEObject = tslib_eidtools::getTSFE();

Die erste Zeile initialisert den Frontent User und gibt uns diesen als Objekt zurück. Dabei wird auch eine Verbindung zur Datenbank hergestellt. Um jetzt noch das komplette TSFE zur Verfügung zu haben rufen wir in der zweiten Zeile die getTSFE Methode auf. Im Weiteren können wir ganz normal auch TYPO3 Funktionalitäten benutzen und eine entsprechende Rückgabe an unseren AJAX Request geben. Möchten wir zB explizit JSON als Format zurückgeben können wir im AJAX Call einen dataType definieren und im PHP einfach json_encode($content); zurück geben. Damit kann man in der success Funktion dann auf das JSON Objekt zugreifen. Beispiel:

$.ajax({
    url: '/?eID=helloworld',
    dataType: 'json',
    success: function(result) {
        alert('Hello ' + result.myResult);
    },
});
class unsereKlasse {

    public function main() {
        $feUserObject = tslib_eidtools::initFeUser();
        $TSFEObject = tslib_eidtools::getTSFE();
        return json_encode(array('myResult' => 'World'));
    }

}

$output = t3lib_div::makeInstance('unsereKlasse');
echo $output->main();

Das war es soweit zum Frontend. Kommen wir noch zum Backend, hier hatte ich ja gesagt das es einen Weg per ajaxID gibt. Machen wir es kurz und schmerzlos :-) Ihr habt eine Extension in der wir in die ext_localconf.php folgendes eintragen

$TYPO3_CONF_VARS['BE']['AJAX']['tx_extkey::helloworld'] = t3lib_extMgm::extPath($_EXTKEY) . 'classes/class.tx_extkey_helloworld_ajax.php:tx_extkey_helloworld_ajax->sayHello';

OHA, was ist das ;-) Gang einfach, ich schreibe es nochmal so

$TYPO3_CONF_VARS['BE']['AJAX']['tx_extkey::key'] = 'pfad/datei.php:klassenname->methodenname';

Ich denke jetzt ist es verständlicher und bedarf keiner weiteren Worte :-) oder doch ? Ok! In unserer Datei class.tx_extkey_helloworld_ajax.php die im Ordner classes liegt gibt es also eine Klasse mit dem Namen tx_extkey_helloworld_ajax in der eine Methode sayHello ist. Mit dieser Zeile haben wir unser AJAX Script erstmal registriert! Ein Aufruf aus einem Modul etc. ist jetzt relativ einfach

$url = $this->doc->backPath . 'ajax.php?ajaxID=tx_extkey::helloworld';

Diese Url ruft Ihr jetzt per AJAX API über jQuery oder extJS (seit 4.3 fest im Core) auf. Dabei wird dann die oben gannten Klasse->Methode aufgerufen und liefert das Ergebnis der Methode zurück. So, der Kaffee ist leer und somit auch das Tutorial zu ende! Ich hoffe ich konnte euch einen kleinen grundlegenden Einstieg verschaffen. Wenn Ihr noch Fragen, Anregungen, Lob oder Kritik habt, nutzt bitte die Kommentarfunktion!

Cheers und bis zum nächsten mal,
Julian


Was this tutorial helpful? So, you can donate some money to the tutorial author via Paypal.