Creating a new client action

Client actions are the client-side 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 OpenERP Web object
  • The OpenERP Web object itself, which must inherit from openerp.web.Widget()

Our example will be the actual code for the widgets client action (a client action displaying a res.widget object, used in the homepage dashboard of the web client):

// Registers the object 'openerp.web_dashboard.Widget' to the client
// action tag 'board.home.widgets'
openerp.web.client_actions.add(
    'board.home.widgets', 'openerp.web_dashboard.Widget');
// This object inherits from View, but only Widget is required
openerp.web_dashboard.Widget = openerp.web.View.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 $element property and the object is started.

If the client action takes parameters, these parameters are passed in as a second positional parameter to the constructor:

init: function (parent, params) {
    // execute the Widget's init
    this._super(parent);
    // 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 = params.widget_id;
}

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

Note

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.

Although generally speaking client actions are not really interacted with.

start: function () {
    return $.when(
        this._super(),
        // Simply read the res.widget object this action should display
        new openerp.web.DataSet(this, 'res.widget').read_ids(
            [this.widget_id], ['title'], this.on_widget_loaded));
}

The client action can then behave exactly as it wishes to within its root (this.$element). 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(
        '/web_dashboard/widgets/content?session_id=%s&widget_id=%d',
        this.session.session_id, widget.id);
    this.$element.html(QWeb.render('HomeWidget.content', {
        widget: widget,
        url: url
    }));
}