Client actions

Client actions are the client-side version of OpenERP’s “Server Actions”: instead of allowing for semi-arbitrary code to be executed in the server, they allow for execution of client-customized code.

On the server side, a client action is an action of type ir.actions.client, which has (at most) two properties: a mandatory tag, which is an arbitrary string by which the client will identify the action, and an optional params which is simply a map of keys and values sent to the client as-is (this way, client actions can be made generic and reused in multiple contexts).

General Structure

In the OpenERP Web code, a client action only requires two pieces of information:

  • Mapping the action’s tag to an object
  • Providing said object. Two different types of objects can be mapped to a client action:

The major difference is in the lifecycle of these:

  • if the client action maps to a function, the function will be called when executing the action. The function can have no further interaction with the Web Client itself, although it can return an action which will be executed after it.

    The function takes 2 parameters: the ActionManager calling it and the descriptor for the current action (the ir.actions.client dictionary).

  • if, on the other hand, the client action maps to a Widget(), that Widget() will be instantiated and added to the web client’s canvas, with the usual Widget() lifecycle (essentially, it will either take over the content area of the client or it will be integrated within a dialog).

For example, to create a client action displaying a res.widget object:

// Registers the object 'openerp.web_dashboard.Widget' to the client
// action tag 'board.home.widgets'
    'board.home.widgets', 'instance.web_dashboard.Widget');
instance.web_dashboard.Widget = instance.web.Widget.extend({
    template: 'HomeWidget'

At this point, the generic Widget() lifecycle takes over, the template is rendered, inserted in the client DOM, bound on the object’s $el property and the object is started.

The second parameter to the constructor is the descriptor for the action itself, which contains any parameter provided:

init: function (parent, action) {
    // execute the Widget's init
    // board.home.widgets only takes a single param, the identifier of the
    // res.widget object it should display. Store it for later
    this.widget_id = action.params.widget_id;

More complex initialization (DOM manipulations, RPC requests, ...) should be performed in the start() method.


As required by Widget()‘s contract, if start() executes any asynchronous code it should return a $.Deferred so callers know when it’s ready for interaction.

start: function () {
    return $.when(
        // Simply read the res.widget object this action should display
        new instance.web.Model('res.widget').call(
            'read', [[this.widget_id], ['title']])

The client action can then behave exactly as it wishes to within its root (this.$el). In this case, it performs further renderings once its widget’s content is retrieved:

on_widget_loaded: function (widgets) {
    var widget = widgets[0];
    var url = _.sprintf(
    this.$el.html(QWeb.render('HomeWidget.content', {
        widget: widget,
        url: url