Project

General

Profile

Feature #17970 » ajax_manual_v2.txt

Administrator Admin, 2008-01-09 16:07

 
==== AJAX in the TYPO3 Backend ====

In TYPO3 4.2beta1 a new model for writing AJAX code in the TYPO3 Backend was introduced. Although there were some parts in the TYPO3 Backend that used AJAX already, they are now unified into a single interface that handles errors and dispatches the different calls to their final locations. This way it is ensured that e.g. a BE user is logged in and all TYPO3 variables are loaded.
The whole architecture builds on top of successful techniques developers already know. It's a mixture between the eID concept from the TYPO3 Frontend, the hooking idea we know from other places in TYPO3, piped through a single small AJAX file "typo3/ajax.php" that creates a PHP AJAX object to see if an error occured or not. If something went wrong, the X-JSON header is set to false and the client-side AJAX request (an AJAX responder in the Prototype Javascript framework) will know that there is an error.

==== In-Depth Analysis ====

=== Client-Side programming ===

On the client-side we are using the Prototype JS library (located in typo3/contrib/prototype/prototype.js). If you have used it already, you know that you can make AJAX calls with AJAX.Request, AJAX.Updater and AJAX.PeriodicalUpdater. We extended the library and hooked in these objects, or better: in the callbacks users can define. If an AJAX request is made to our server-side component (typo3/ajax.php), everything developers need to do is to call this URL and add a unique, already registered parameter for their ajaxID. Their defined "onComplete" and "onSuccess" are only rendered if the X-JSON header is set to true by the server-side script. If the X-JSON header is set to false, the Responder checks if there is a callback function named "onT3Error" and executes it instead of the onComplete method. If the "onT3Error" method is not defined, the default TYPO3 error handler will be displaying the error in the TYPO3 backend. If the X-JSON header is set to false, the "onSuccess" callback will not be executed as well as the but an error message will be shown in the notification area. This behaviour is done automatically with every AJAX call to "ajax.php" made through Prototype's AJAX classes. This responder is also only active if "typo3/js/common.js" is added to the base script.

=== Server-side programming ===

If you look into "typo3/ajax.php", it is only a small dispatcher script. It checks for an ajaxID in the TYPO3_CONF_VARS['BE']['AJAX'] array and tries to execute the function pointer. The function has two parameters, where the first (an array) is not used yet. The second parameter is the TYPO3 AJAX Object (located in typo3/classes/typo3ajax.php) that is used to add the content that should be returned as the server-response to the Javascript part, or the error message that should be displayed. The X-JSON header will be set depending if "setError()" was called on this AJAX object. You can also specify if the object should return the result in a valid XML object tree, as text/html (default) or as a JSON object, see below.

The "ajaxID" is a unique identifier and can be used to override the existing ajax calls. Therefore you can extend existing AJAX calls that already exist in the backend by redirecting it to your function. But be aware of the side-effects of this feature: Other extensions could overwrite this function as well (similar problem as with XCLASSing or single inheritance in OOP).

Also, for every TYPO3 request, you will now have a TYPO3_REQUESTTYPE variable that can be used for bitwise comparison. You can now check if you're in Backend or Frontend or in an valid AJAX request with
if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX)
to see if you're calling through the new AJAX interface.

=== Different Content Formats ===

As with every AJAX response you can send it in different response formats.

* text/html - plain text
* text/xml - strict XML formatting
* application/json - JSON notation

You can also specify the contentFormat in the AJAX object like this:
$ajaxObj->setContentFormat('json');

You can choose between "plain" (default), "xml" and "json" as a keyword there.

Here are the specifics for each format:

== Plain Text ==

The content array in the backend will be concatenated and returned uninterpreted.
The result will be available in the transport object as a string through "xhr.responseText".

== XML ==

The content needs to be valid XML and will be available in javascript as "xhr.responseXML".

== JSON ==

The content is put through the service in "typo3/contrib/json/json.php" and is then available in JSON notation through the second parameter in the onComplete / onSuccess methods, and additionally in the "responseText" part of the transport object ("xhr.responseText").



==== What to do when you're developing AJAX in the TYPO3 Backend ====

This should be a small guide for you to use this new feature in your AJAX scripts.

=== Server-Side ===

1) Register your unique ajaxID, at best prepended with your extID, in the TYPO3 backend by adding the following line to your "ext_localconf.php" (btw: This way you can also overwrite existing AJAX calls):

$TYPO3_CONF_VARS['BE']['AJAX']['yourExt_ajaxID'] = 'filename:object->method';

A working example would be:
$TYPO3_CONF_VARS['BE']['AJAX']['cms_pagetreeExpandCollapse'] = 'typo3/alt_db_navframe.php:SC_alt_db_navframe->ajaxExpandCollapse';

2) Create a target method to do the logic on the server-side: Similar to the existing hooking mechanism, as with every "callUserFunction", the target method (here: ajaxExpandCollapse) will have two function parameters. The first one is an array of params (not used right now), the second is the TYPO3 AJAX Object (see typo3/classes/class.typo3ajax.php for all available methods). You should use this to set the content you want to output or to write the error message if something went wrong.

public function ajaxExpandCollapse($params, &$ajaxObj) {
$this->init();
// do the logic...
if (empty($this->tree)) {
$ajaxObj->setError("An Error occured");
} else {
// the content is an array that can be set through $key / $value pairs as parameter
$ajaxObj->addContent('tree', "The tree works...");
}
}


So, the server-side part is now complete. Let's move over to the client-side.

=== Client-part ===

3) In order for you to use Javascript you have to add this two lines of PHP code in your PHP script (available in template.php, your template document). So it is loaded

$this->doc->loadJavascriptLib('contrib/prototype/prototype.js');
$this->doc->loadJavascriptLib('js/common.js');

4) With prototype on the client side, it's quite simple to add a new AJAX request in Javascript:

new AJAX.Request('ajax.php', {
method: 'get',
parameters: 'ajaxID=pagetreeExpandCollapse',
onComplete: function(xhr, json) {
// display results, should be "The tree works"
}.bind(this),
onT3Error: function(xhr, json) {
// display error message, will be "An Error occured" if an error occured
}.bind(this)
});

You can see, that it's almost the same, except that we introduce a new callback function "onT3Error", which is optional. It is called if the method "setError" on the server-side was called. Otherwise "onComplete" will be called. If you do not define "onT3Error", then the error message will be shown in the TYPO3 notification area in the backend. Our AJAX responders also work with the "onSuccess" callback, but the onT3Error is only executed with "onComplete".

This should be all. Please note that our TYPO3 BE AJAX mechanism works best with the prototype JS library. If you want to create similar approaches for other JS frameworks, have a look at "typo3/js/common.js".

Benjamin Mack
(4-4/6)