< Locate

Geostatistics  >

21. AJAX

21.1. Introduction

CartoWeb implements an AJAX layer, enabling asynchronous update of the HTML GUI.

21.1.1. Browser Compatibility

Browser compatibility:

  • Mozilla 1.7+
  • Firefox 1.0.7+
  • Internet Explorer 6+
  • Safari 1.3.2+

Known browser incompatibility:

  • Opera
  • Internet Explorer 5 for Mac
  • Konqueror

21.2. Make Your Project AJAX Enabled

To enable your project with AJAX, it is recommended that you build your project based on demoCW3 or test_main projects (CartoWeb version 3.3.0 or higher). A project based on demoCW3 won't need any tuning. A project based on test_main will require the following:

  • Enable AJAX in your client.ini (or client.ini.in):

If you have a project running since version 3.2.0 or before, and want to enable AJAX, you'll need to:

  • Enable AJAX in your client.ini (or client.ini.in)
  • Adapt your cartoclient.tpl, mainmap.tpl and all redefined plugin templates (if they are based on test_main or demoCW3 project templates from CartoWeb version <= 3.2.0).

21.2.1. Client.ini Configuration

Add the ajaxOn directive and set it to true in your /project/[yourProjectName]/client_conf/client.ini or /project/[yourProjectName]/client_conf/client.ini.in

ajaxOn = true

21.2.2. Plugin Ajaxisation Generalities

There are several steps needed to add ajax support to a plugin :

  • PHP
  • javascript
  • template

21.2.3. PHP side

Your plugin php class must implements the Ajaxable interface.

class ClientYourPlugin extends ClientPlugin implements Ajaxable { ...

You can then add two functions:

  • ajaxGetPluginResponse
  • ajaxHandleAction

21.2.3.1. ajaxGetPluginResponse

ajaxGetPluginResponse will send back your plugin's response. It behaves the same way as the usual renderForm function.

instead of doing :

$template->assign($some_content);

you do :

$ajaxPluginResponse->addHtmlCode('some_variable_name', $some_content);
$ajaxPluginResponse->addVariable('another_variable_name', $some_content);

HtmlCode and Variable are pretty much the same thing, it only differentiates the treatments between html output and javascript variables.

21.2.3.2. ajaxHandleAction

ajaxHandleAction is where you specify which plugin(s) is activated when an action is triggered through your plugin. The content is usualy a switch on the action name:

switch ($actionName) {
    case 'YourPlugin.SomeAction':
        $pluginEnabler->disableCoreplugins();
        $pluginEnabler->enablePlugin('images');
        $pluginEnabler->enablePlugin('yourplugin');
    break;
    case 'YourPlugin.AnotherAction':            
        $pluginEnabler->disableCoreplugins();
        $pluginEnabler->enablePlugin('yourplugin');
    break;
}

You must explicitly enable your plugin

$pluginEnabler->enablePlugin('yourplugin');

otherwise your plugin will not send back anything.

disableCoreplugins(); explicitly deactivate all coreplugin. It means nothing will be sent back to the browser.

You can activate plugin case by case, for example:

$pluginEnabler->disableCoreplugins();
$pluginEnabler->enablePlugin('images');

will only enable the images coreplugin and the map will then be refreshed.

21.2.4. Javascript browser's side

Create a new javascript file named YourPlugin.ajax.js

Place it in plugins/yourPlugin/htdocs/js/

Add it to your cartoclient.tpl header:

<script type="text/javascript" src="{r type=js plugin=yourPlugin}YourPlugin.ajax.js{/r}"></script>}

be careful to not place it before {include file="cartoclient_ajaxHeader.tpl"}, you will get a javscript error because the plugin's javascript code use some objects which are defined only in files inluded via the cartoclient_ajaxHeader.tpl file.

The YourPlugin.ajax.js contains basicaly two parts, one to trigger the action and another to handle the answer and update your html/javascript

21.2.4.1. Ajax Answer Handling

AjaxPlugins.YourPlugin = {
  
    handleResponse: function(pluginOutput) {
        /* Plugin general behaviour */
        
        if (pluginOutput.variables.variable_name) {
        // do something with your variable
        alert(pluginOutput.variables.another_variable_name);
        }

        AjaxHandler.updateDomElement('target_id', 'innerHTML',
                                     pluginOutput.htmlCode.some_variable_name);
    }  
};
}

The answer sent by PHP is handled in handleResponse. Here you recover the variables and htmlCodes.

The function updateDomElement will handle all the html insertion. It takes 3 parameters:

  • the target id of the existing element in your current html which will serve as container for the new content.
  • the insertion methode, always 'innerHTML'.
  • the new content.

21.2.4.2. Ajax Action Triggering

In this part, you simply define all your actions and what to do before, when and after the actions are triggered.

AjaxPlugins.YourPlugin.Actions = {};
// always empty, it only define a Actions object which will store our various actions.

AjaxPlugins.YourPlugin.Actions.SomeAction = {

    buildPostRequest: function(argObject) {
        return AjaxHandler.buildPostRequest();
    },
    .
    onBeforeAjaxCall: function(argObject) {
        Logger.note('Output something in the JSTraceDebugger window');
        callSomeJavascriptFunctions();
    },

    onAfterAjaxCall: function(argObject) {
        Logger.note('Output something in the JSTraceDebugger window');
        callSomeJavascriptFunctions();
    },

    onBeforeAjaxCallGeneral: function(argObject) {
        Logger.note('Output something in the JSTraceDebugger window');
        callSomeJavascriptFunctions();
    },

    onAfterAjaxCallGeneral: function(argObject) {
        Logger.note('Output something in the JSTraceDebugger window');
        callSomeJavascriptFunctions();
    },

    oneCustomFunction: function() {
        Logger.note('Output something in the JSTraceDebugger window');
        // you can also define functions 
        ...
    }
};

AjaxPlugins.YourPlugin.Actions.AnotherAction = {

    buildPostRequest: function(argObject) {
        return AjaxHandler.buildPostRequest();
    }
};

Warning

BE CAREFUL FOR CLOSING "," and ";" !!!!

these are json syntax and it is a bit different than your usual javascript.

  • buildPostRequest is always executed, it simply parses your html and recover all the inputs (text, hidden, select, radio, checkbox, password, textarea) values and send them to the server.
  • onBeforeAjaxCall and onAfterAjaxCall are optional. These functions are called before and after the action. For example if you want to modify some inputs value just before it's being sent to the server. Or you want too add some post-treatments. Note that onAfterAjaxCall is called AFTER the response is being treated in the normal handleResponse stage (see Section 21.2.4.1, “Ajax Answer Handling”).
  • onBeforeAjaxCallGeneral and onAfterAjaxCallGeneral are optional. These functions are called EVERYTIME an AJAX call is triggered by ANY plugins. If you add these functions in your plugin, the functions will be called even if the action was triggered by another plugin. onBeforeAjaxCallGeneral is called BEFORE onBeforeAjaxCall. onAfterAjaxCallGeneral is called AFTER onAfterAjaxCall.
21.2.4.2.1. Add Event

If the html fragment your are inserting must implement on-the-fly javascript event, you can attach some event on existing elements via the attachAction function:

AjaxHandler.attachAction('target_element_id', 'type_of_event', 'callback_function', json_defined_arguments);

for example:

AjaxHandler.attachAction('pan_n', 'click', 'Location.Pan', {source: 'button'});

21.2.4.2.2. Custom Functions

You can define custom functions as well, see the oneCustomFunction above. But you will need to explicitly call these functions from buildPostRequest, onBeforeAjaxCall or onAfterAjaxCall.

The function is called like this: this.oneCustomFunction();

21.2.4.2.3. Log Messages

You can output some notice or warning in the JSTraceDebugger windows by adding:

Logger.note('Some text that will appear in the debugger');

You can also use 'send', 'header', 'error', 'warn', 'trace' or 'confirm'. They have slightly different styling. See file Logger.js for details.

21.2.4.3. Initialize plugin

You may want to call some functions or define some variables on page load. To do so simply add your plugin into the AjaxPlugins.initializablePlugins array, like this:

// add your plugin to the list of Ajax initializable plugins
AjaxPlugins.initializablePlugins.push(AjaxPlugins.YourPluginName);

Add this after your main

AjaxPlugins.YourPluginName = {...};

21.2.5. Templates Adaptation

To trigger the actions defined in YourPlugin.ajax.js, you simply call them like this:

<input type="button" value="{t}ok{/t}" onclick="return CartoWeb.trigger('YourPlugin.AnotherAction');" />
}

or if you want to provide a non-ajax fallback, you can do it like that:

<input type="button" value="{t}ok{/t}" onclick="return CartoWeb.trigger('YourPlugin.AnotherAction', 'doSubmit()');" />
}

Warning

Adapting your templates is a tricky bit. Unless you customized your templates thoroughly, we recommend that you start over again your templates customization using demoCW3 or test_main as a basis, as these projects templates are AJAX ready.

We recommend that you diff your cartoclient.tpl, mainmap.tpl and all redefined plugin templates with the upstream. This is the best way to be up to date, especially if you use the latest CVS version of CartoWeb.

valid xhtml 1.0 valid css