Making RPC calls to the server

Sooner or later, your widget will need to look up some data from the server. This recipe shows you how to do that. We'll replace the hard coded list of users in the many2one_buttons widget with a list queried from the server, depending on the field's domain.

Getting ready

This recipe is just a modified version of the previous recipe, Using client side templates: QWeb code, so grab a copy of it and use it to create addon ch15_r03.

How to do it...

We just have to adapt some JavaScript code at the right places:

  1. Require the data and model packages in static/src/js/ch15_r03.js:
    odoo.define('ch15_r01', function(require)
    {
        var core = require('web.core'),
            data = require('web.data'),
            model = require('web.Model'),
            form_common = require('web.form_common');
  2. Delete the hard-coded list in init to have it only set up the event listener:
            init: function()
            {
                var result = this._super.apply(this, arguments);
                this.on(
                    'change:effective_readonly', this,
                    this.effective_readonly_changed)
                return result;
            },
  3. Query the server for the list we want in willStart:
            willStart: function()
            {
                var deferred = new jQuery.Deferred(),
                    self = this;
                self.user_list = {};
                new data.Query(new model(this.field.relation), ['display_name'])
                .filter(this.field.domain)
                .all()
                .then(function(records)
                {
                    _.each(records, function(record)
                    {
                        self.user_list[record.id] = record;
                        self.user_list[record.id].name = record.display_name;
                    });
                    deferred.resolve();
                });
                return jQuery.when(
                    this._super.apply(this, arguments),
                    deferred
                );
            },

Now you should see all users of your system, not just the two hard-coded ones as you did before. Also, the widget can be used for any many2one fields now, because it just queries what is available and doesn't need any knowledge about this beforehand. If you set a domain on the field, the buttons will be restricted to records matching this domain. In this specific case, you might want to restrict the selection to users of the group Sale | User.

How it works...

The willStart function is called before rendering, and, more importantly, returns a deferred object that must be resolved before rendering starts. So in a case like ours, where we need to run an asynchronous action before rending can occur, this is the right function to do it.

The data and model packages we required in the new code provide access to classes dealing with data access. The model class provides low-level access to model functions like search or read, or in this case, search_read. We could have just used them, but they are less convenient than the Query class, which behaves more like you'd expect from JavaScript objects: you can chain calls and set things like the domain in a persistent way on the object as opposed to passing it as a parameter, as you'd have to do with the model class. In the end, you'll be executing basically the same RPC functions, so this is up to your personal preference.

In any case, we'll have to collect the results asynchronously in our success handler. This will set up the internal data structure user_list the same way we did before in the hard-coded version, which is great, because this way, we don't have to change anything else.

Note that we request the field display_name here instead of name, because we can be sure that every model has a field display_name, whereas that's not guaranteed with the field name. Then we just assign the name property the same value as display_name, this, again, is in order not to have to change existing code more than necessary. Do this too instead of a lot of overrides if you just need to divert display to another field or something similar. For details about the display_name field, refer to the Chapter 4, Application Models, recipe Define the Model representation and order.

The end of the handler contains the crucial part, resolving the deferred object we created before. This, in combination with returning the deferred object wrapped together with super's result in a new deferred object created by the jQuery.when call, causes rendering to only happen after the values are fetched and whatever asynchronous action super was busy with finished too. This way, you can be sure in the template code that widget.user_list is accessible and contains the values we need.

There's more...

The AbstractField class comes with a couple of interesting properties, one of which we used above. The field property contains the output of the model's fields_get function for the field the widget is displaying. Apart from the relation key that gives you the comodel for x2x fields or the domain, you can also use it to query the field's string, size or whatever other property you can set on the field during model definition.

Another helpful property is options, which contains data passed via the options attribute in the form definition. This is already JSON parsed, so you can access it like any object.

See also

Odoo's RPC heavily relies on jQuery's deferred objects, so it can't be repeated often enough that you should dive into jQuery's documentation about this: https://api.jquery.com/jQuery.Deferred

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.255.44