How to do it...

Follow these steps to add a new view called m2m_group:

  1. Add a new view type in ir.ui.view:
class View(models.Model):
_inherit = 'ir.ui.view'

type = fields.Selection(selection_add=[('m2m_group', 'M2m Group')])
  1. Add a new view mode in ir.actions.act_window.view:
class ActWindowView(models.Model):
_inherit = 'ir.actions.act_window.view'

view_mode = fields.Selection(selection_add=[('m2m_group', 'M2m group')])
  1. Add a new method by inheriting from the base model. This method will be called from the JavaScript model (see step 4 for more details):
class Base(models.AbstractModel):
_inherit = 'base'

@api.model
def get_m2m_group_data(self, domain, m2m_field):
records = self.search(domain)
result_dict = {}
for record in records:
for m2m_record in record[m2m_field]:
if m2m_record.id not in result_dict:
result_dict[m2m_record.id] = {
'name': m2m_record.display_name,
'children': [],
'model': m2m_record._name
}
result_dict[m2m_record.id]['children'].append({
'name': record.display_name,
'id': record.id,
})
return result_dict
  1. Add a new file called /static/src/js/m2m_group_model.js, and add the following content to it:
odoo.define('m2m_group.Model', function (require) {
'use strict';

var AbstractModel = require('web.AbstractModel');

var M2mGroupModel = AbstractModel.extend({
get: function () {
return this.data;
},
load: function (params) {
this.modelName = params.modelName;
this.domain = params.domain;
this.m2m_field = params.m2m_field;
return this._fetchData();
},
reload: function (handle, params) {
if ('domain' in params) {
this.domain = params.domain;
}
return this._fetchData();
},
_fetchData: function () {
var self = this;
return this._rpc({
model: this.modelName,
method: 'get_m2m_group_data',
kwargs: {
domain: this.domain,
m2m_field: this.m2m_field
}
}).then(function (result) {
self.data = result;
});
},
});

return M2mGroupModel;

});
  1. Add a new file called /static/src/js/m2m_group_controller.js, and add the following content to it:
odoo.define('m2m_group.Controller', function (require) {
'use strict';

var AbstractController = require('web.AbstractController');
var core = require('web.core');
var qweb = core.qweb;

var M2mGroupController = AbstractController.extend({
custom_events: _.extend({}, AbstractController.prototype.custom_events, {
'btn_clicked': '_onBtnClicked',
}),
renderButtons: function ($node) {
if ($node) {
this.$buttons = $(qweb.render('ViewM2mGroup.buttons'));
this.$buttons.appendTo($node);
this.$buttons.on('click', 'button', this._onAddButtonClick.bind(this));
}
},
_onBtnClicked: function (ev) {
this.do_action({
type: 'ir.actions.act_window',
name: this.title,
res_model: this.modelName,
views: [[false, 'list'], [false, 'form']],
domain: ev.data.domain,
});
},
_onAddButtonClick: function (ev) {
this.do_action({
type: 'ir.actions.act_window',
name: this.title,
res_model: this.modelName,
views: [[false, 'form']],
target: 'new'
});
},


});

return M2mGroupController;

});
  1. Add a new file called /static/src/js/m2m_group_renderer.js, and add the following content to it:
odoo.define('m2m_group.Renderer', function (require) {
'use strict';

var AbstractRenderer = require('web.AbstractRenderer');
var core = require('web.core');

var qweb = core.qweb;

var M2mGroupRenderer = AbstractRenderer.extend({
events: _.extend({}, AbstractRenderer.prototype.events, {
'click .o_primay_button': '_onClickButton',
}),
_render: function () {
var self = this;
this.$el.empty();
this.$el.append(qweb.render('ViewM2mGroup', {
'groups': this.state,
}));
return this._super.apply(this, arguments);
},
_onClickButton: function (ev) {
ev.preventDefault();
var target = $(ev.currentTarget);
var group_id = target.data('group');
var children_ids = _.map(this.state[group_id].children, function (group_id) {
return group_id.id;
});
this.trigger_up('btn_clicked', {
'domain': [['id', 'in', children_ids]]
});
}
});

return M2mGroupRenderer;

});
  1. Add a new file called /static/src/js/m2m_group_view.js, and add the following content to it:
odoo.define('m2m_group.View', function (require) {
'use strict';

var AbstractView = require('web.AbstractView');
var view_registry = require('web.view_registry');
var M2mGroupController = require('m2m_group.Controller');
var M2mGroupModel = require('m2m_group.Model');
var M2mGroupRenderer = require('m2m_group.Renderer');


var M2mGroupView = AbstractView.extend({
display_name: 'Author',
icon: 'fa-id-card-o',
config: {
Model: M2mGroupModel,
Controller: M2mGroupController,
Renderer: M2mGroupRenderer,
},
viewType: 'm2m_group',
groupable: false,
init: function (viewInfo, params) {
this._super.apply(this, arguments);
var attrs = this.arch.attrs;

if (!attrs.m2m_field) {
throw new Error('M2m view has not defined "m2m_field" attribute.');
}

// Model Parameters
this.loadParams.m2m_field = attrs.m2m_field;
},
});

view_registry.add('m2m_group', M2mGroupView);

return M2mGroupView;

});
  1. Add the QWeb template for the view to the /static/src/xml/qweb_template.xml file:
<t t-name="ViewM2mGroup">
<div class="row ml16 mr16">
<div t-foreach="groups" t-as="group" class="col-3">
<t t-set="group_data" t-value="groups[group]" />
<div class="card mt16">
<img class="card-img-top" t-attf-src="/web/image/#{group_data.model}/#{group}/image"/>
<div class="card-body">
<h5 class="card-title mt8"><t t-esc="group_data['name']"/></h5>
</div>
<ul class="list-group list-group-flush">
<t t-foreach="group_data['children']" t-as="child">
<li class="list-group-item"><i class="fa fa-book"/> <t t-esc="child.name"/></li>
</t>
</ul>
<div class="card-body">
<a href="#" class="btn btn-sm btn-primary o_primay_button" t-att-data-group="group">View books</a>
</div>
</div>
</div>
</div>
</t>

<div t-name="ViewM2mGroup.buttons">
<button type="button" class="btn btn-primary">
Add Record
</button>
</div>
  1. Add all of the JavaScript files to the backend assets:
...
<script type="text/javascript" src="/my_library/static/src/js/m2m_group_view.js" />
<script type="text/javascript" src="/my_library/static/src/js/m2m_group_model.js" />
<script type="text/javascript" src="/my_library/static/src/js/m2m_group_controller.js" />
<script type="text/javascript" src="/my_library/static/src/js/m2m_group_renderer.js" />
...
  1. Finally, add our new view for the library.book model:
    <record id="library_book_view_author" model="ir.ui.view">
<field name="name">Library Book Author</field>
<field name="model">library.book</field>
<field name="arch" type="xml">
<m2m_group m2m_field="author_ids" color_field="color">
</m2m_group>
</field>
</record>
  1. Add m2m_group in the book action:
...
<field name="view_mode">tree,m2m_group,form</field>
...

Update the my_library module to open the book view, and then, from the view switcher, open the new view that we just added. This will look as follows:

Odoo views are very easy to use and are very flexible. However, it is often the case that easy and flexible things have complex implementations under the hood. This is the same case with the Odoo JavaScript views: they are easy to use, but complex to implement. It consists of lots of components, like the model, renderer, controller, view, QWeb template, and so on. In the next section, we have added all of the required components for the views and have also used a new view for the library.book model. If you don't want to add everything manually, grab a module from the example file in this book's GitHub repository.
..................Content has been hidden....................

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