I am creating one module where I have a Many2many
field and I would like to convert it into a checkbox group. I have written this in my XML view to achieving it
<field name="location_ids" widget="many2many_checkboxes"/>
But the field is shown all the options in a long column. I would like to show the options in multiple rows as in the following image:
I think I have found a good approach for you.
First I have search the original template which is rendered with the widget many2many_checkboxes
. This one:
<t t-name="FieldMany2ManyCheckBoxes">
<div t-foreach="widget.get('records')" t-as="record">
<div class="o_checkbox">
<input t-if="widget.get('value').indexOf(record[0]) !== -1" type="checkbox" t-att-data-record-id="JSON.stringify(record[0])" checked="checked"/>
<input t-if="widget.get('value').indexOf(record[0]) === -1" type="checkbox" t-att-data-record-id="JSON.stringify(record[0])"/>
<span/>
</div>
<label class="o_form_label"><t t-esc="record[1]"/></label>
</div>
</t>
So, I have copied the result html code of the group
structure and I have combined it with the template of the widget.
You need to create a xml file with this content and add it to your __manifes__.py
file:
'qweb': ['static/src/xml/many2many_checkboxes.xml', ]
The code of many2many_checkboxes.xml
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-extend="FieldMany2ManyCheckBoxes">
<t t-jquery="div:first" t-operation="replace">
<div class="o_group">
<table class="o_group o_inner_group o_group_col_6">
<tbody>
<t t-foreach="widget.m2mValues" t-as="record">
<t t-if="record_parity == 'odd'">
<t t-set="id_for_label" t-value="'o_many2many_checkbox_' + _.uniqueId()"/>
<tr>
<td colspan="1" class="o_td_label">
<label t-att-for="id_for_label" class="o_form_label"><t t-esc="record[1]"/></label>
</td>
<td colspan="1" style="width: 50%;">
<div class="o_checkbox o_form_field_boolean o_form_field">
<div class="o_checkbox">
<input type="checkbox" t-att-id="id_for_label" t-att-data-record-id="JSON.stringify(record[0])"/>
<span/>
</div>
</div>
</td>
</tr>
</t>
</t>
</tbody>
</table>
<table class="o_group o_inner_group o_group_col_6 pull-right">
<tbody>
<t t-foreach="widget.m2mValues" t-as="record">
<t t-if="record_parity == 'even'">
<t t-set="id_for_label" t-value="'o_many2many_checkbox_' + _.uniqueId()"/>
<tr>
<td colspan="1" class="o_td_label">
<label t-att-for="id_for_label" class="o_form_label"><t t-esc="record[1]"/></label>
</td>
<td colspan="1" style="width: 50%;">
<div class="o_checkbox o_form_field_boolean o_form_field">
<div class="o_checkbox">
<input type="checkbox" t-att-id="id_for_label" t-att-data-record-id="JSON.stringify(record[0])"/>
<span/>
</div>
</div>
</td>
</tr>
</t>
</t>
</tbody>
</table>
</div>
</t>
</t>
</templates>
Finally add the field in your form. But without group
elements since we are already adding the group
html elements on the template above. You need to add the this attribute style="display: block;"
in order to keep the position in the grid right.
<separator string="Field name" />
<field name="test_many2many_checkboxes"
widget="many2many_checkboxes"
nolabel="1"
style="display: block;" />
Let me know if this works for you. I have tested with my Odoo 11 instance and it works fine. This is the result with two columns. If you want three columns you will need to adapt the template:
I have checked how Odoo developers have done the table on the "Technical Settings". They are creating one single table instead of two as I do. So maybe there is a better way to do it because I need to loop over all the records twice to build the two tables.
Anyway you are free to improve my code. I only wanted to guide you to the solution. Maybe you can group the records in threes to build the rows.
The template changes a little bit for the version 10, so you need to use this template instead:
<t t-extend="FieldMany2ManyCheckBoxes">
<t t-jquery="div:first" t-operation="replace">
<div class="o_group">
<table class="o_group o_inner_group o_group_col_6">
<tbody>
<t t-foreach="widget.get('records')" t-as="record">
<t t-if="record_parity == 'odd'">
<tr>
<td colspan="1" class="o_td_label">
<label for="o_field_input_28" class="o_form_label" data-original-title="" title="">
<span t-esc="record[1]"/>
</label>
</td>
<td colspan="1" style="width: 50%;">
<div class="o_checkbox o_form_field_boolean o_form_field">
<div class="o_checkbox">
<input t-if="widget.get('value').indexOf(record[0]) !== -1" type="checkbox" t-att-data-record-id="JSON.stringify(record[0])" checked="checked"/>
<input t-if="widget.get('value').indexOf(record[0]) === -1" type="checkbox" t-att-data-record-id="JSON.stringify(record[0])"/>
<span/>
</div>
</div>
</td>
</tr>
</t>
</t>
</tbody>
</table>
<table class="o_group o_inner_group o_group_col_6 pull-right">
<tbody>
<t t-foreach="widget.get('records')" t-as="record">
<t t-if="record_parity == 'even'">
<tr>
<td colspan="1" class="o_td_label">
<label for="o_field_input_28" class="o_form_label" data-original-title="" title="">
<span t-esc="record[1]"/>
</label>
</td>
<td colspan="1" style="width: 50%;">
<div class="o_checkbox o_form_field_boolean o_form_field">
<div class="o_checkbox">
<input t-if="widget.get('value').indexOf(record[0]) !== -1" type="checkbox" t-att-data-record-id="JSON.stringify(record[0])" checked="checked"/>
<input t-if="widget.get('value').indexOf(record[0]) === -1" type="checkbox" t-att-data-record-id="JSON.stringify(record[0])"/>
<span/>
</div>
</div>
</td>
</tr>
</t>
</t>
</tbody>
</table>
</div>
</t>
</t>