diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js
index fc026a332f0..42b31bc2e3c 100644
--- a/addons/web/static/src/js/views/list/list_renderer.js
+++ b/addons/web/static/src/js/views/list/list_renderer.js
@@ -848,8 +848,8 @@ var ListRenderer = BasicRenderer.extend({
},
/**
* Render a single
with the informations for a column. If it is not a
- * field, the th will be empty. Otherwise, it will contains all relevant
- * information for the field.
+ * field or nolabel attribute is set to "1", the th will be empty.
+ * Otherwise, it will contains all relevant information for the field.
*
* @private
* @param {Object} node
@@ -874,7 +874,7 @@ var ListRenderer = BasicRenderer.extend({
if (node.attrs.readOnly) {
$th.addClass('oe_read_only');
}
- if (!field) {
+ if (!field || node.attrs.nolabel === '1') {
return $th;
}
var description = string || field.string;
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js
index 98b85b2270e..a0c7d4d00ce 100644
--- a/addons/web/static/tests/views/list_tests.js
+++ b/addons/web/static/tests/views/list_tests.js
@@ -559,6 +559,19 @@ QUnit.module('Views', {
list.destroy();
});
+ QUnit.test('field with nolabel has no title', async function (assert) {
+ assert.expect(1);
+
+ const list = await createView({
+ View: ListView,
+ model: 'foo',
+ data: this.data,
+ arch: '',
+ });
+ assert.strictEqual(list.$('thead tr:first th:eq(1)').text(), "");
+ list.destroy();
+ });
+
QUnit.test('field titles are not escaped', async function (assert) {
assert.expect(2);
@@ -3207,6 +3220,39 @@ QUnit.module('Views', {
list.destroy();
});
+ QUnit.test('do not sort records when clicking on header with nolabel', async function (assert) {
+ assert.expect(6);
+
+ this.data.foo.fields.foo.sortable = true;
+
+ let nbSearchRead = 0;
+ const list = await createView({
+ View: ListView,
+ model: 'foo',
+ data: this.data,
+ arch: '',
+ mockRPC: function (route) {
+ if (route === '/web/dataset/search_read') {
+ nbSearchRead++;
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.strictEqual(nbSearchRead, 1, "should have done one search_read");
+ assert.strictEqual(list.$('.o_data_cell').text(), "yop10blip9gnap17blip-4");
+
+ await testUtils.dom.click(list.$('thead th[data-name="int_field"]'));
+ assert.strictEqual(nbSearchRead, 2, "should have done one other search_read");
+ assert.strictEqual(list.$('.o_data_cell').text(), "blip-4blip9yop10gnap17");
+
+ await testUtils.dom.click(list.$('thead th[data-name="foo"]'));
+ assert.strictEqual(nbSearchRead, 2, "shouldn't have done anymore search_read");
+ assert.strictEqual(list.$('.o_data_cell').text(), "blip-4blip9yop10gnap17");
+
+ list.destroy();
+ });
+
QUnit.test('use default_order', async function (assert) {
assert.expect(3);
diff --git a/doc/reference/views.rst b/doc/reference/views.rst
index d3c9b7fb60c..a0e4011e1d6 100644
--- a/doc/reference/views.rst
+++ b/doc/reference/views.rst
@@ -1480,6 +1480,9 @@ Possible children elements of the list view are:
``{$name}`` can be ``bf`` (``font-weight: bold``), ``it``
(``font-style: italic``), or any `bootstrap contextual color`_ (``danger``,
``info``, ``muted``, ``primary``, ``success`` or ``warning``).
+ ``nolabel``
+ if set to "1", the column header will remain empty. Also, the column
+ won't be sortable.
.. note::
|