diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index 8239692711e..992af62387e 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -302,6 +302,9 @@ var BasicModel = AbstractModel.extend({ for (var fieldName in element.data) { field = element.fields[fieldName]; + if (!field) { + continue; + } // get relational datapoint if (field.type === 'many2one') { @@ -842,18 +845,32 @@ var BasicModel = AbstractModel.extend({ }); }, /** - * Set and return the fieldattrs on a record element. + * Set fieldNames. + * Set fields on a record element (current fields as defaults) + * Set fieldattrs. * It is mostly useful for the cases where a record element is shared * between various views, such as a one2many with a tree and a form view. * * @param {string} recordID a valid element ID - * @param {Object} attrs the new field attrs - * @return {Object} the previous field attrs + * @param {Object} props + * @param {Object} props.fieldNames + * @param {Object} props.fields + * @param {Object} props.fieldAttrs + * @return {Object} + * @return {Object} result.fieldNames the previous field names + * @return {Object} result.fields the previous description fields + * @return {Object} result.fieldattrs the previous field attrs */ - setFieldAttrs: function (recordID, attrs) { + setFieldProps: function (recordID, props) { var record = this.localData[recordID]; - var result = record.fieldAttrs; - record.fieldAttrs = attrs; + var result = { + fieldNames: record.fieldNames, + fields: record.fields, + fieldAttrs: record.fieldAttrs, + }; + record.fieldNames = props.fieldNames; + record.fields = _.defaults(props.fields, record.fields); + record.fieldAttrs = props.fieldAttrs; return result; }, /** @@ -2100,6 +2117,9 @@ var BasicModel = AbstractModel.extend({ if (element.type === 'record') { for (var fieldName in element.data) { var field = element.fields[fieldName]; + if (!field) { + continue; + } if (_.contains(['one2many', 'many2one', 'many2many'], field.type)) { var relationalElement = this.localData[element.data[fieldName]]; diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js index 22ec34f714b..e581b222417 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -63,24 +63,28 @@ return AbstractRenderer.extend({ * @returns {Object} */ _getFieldValues: function (record) { - return _.mapObject(record.data, function (value, name) { + var result = {}; + _.each(record.fieldNames, function (name) { var field = record.fields[name]; + var value = record.data[name]; + result[name] = value; if (field.type === 'many2one') { - return value.data ? value.data.id || false : false; + result[name] = value.data ? value.data.id || false : false; } if (field.type === 'one2many' || field.type === 'many2many') { if (value) { - return _.pluck(value.data, 'res_id'); + result[name] = _.pluck(value.data, 'res_id'); } else { - return []; + result[name] = []; } } if (field.type === 'boolean') { // we want an explicit false value, not null if it is unset - return value || false; + result[name] = value || false; } - return value; }); + result.id = record.data.id; + return result; }, /** * Render the view diff --git a/addons/web/static/src/js/views/view_dialogs.js b/addons/web/static/src/js/views/view_dialogs.js index ab9588dc740..5ca2cd5c14e 100644 --- a/addons/web/static/src/js/views/view_dialogs.js +++ b/addons/web/static/src/js/views/view_dialogs.js @@ -141,7 +141,7 @@ var FormViewDialog = ViewDialog.extend({ */ destroy: function () { if (this.recordID && this.fieldAttrs) { - this.model.setFieldAttrs(this.recordID, this.fieldAttrs); + this.setFieldProps(this.recordID, this.previousFieldProps); } this._super.apply(this, arguments); }, @@ -168,8 +168,11 @@ var FormViewDialog = ViewDialog.extend({ fields_view_def.then(function (fields_view) { if (self.recordID) { - self.fieldAttrs = - self.model.setFieldAttrs(self.recordID, fields_view.fieldAttrs); + self.previousFieldProps = self.model.setFieldProps(self.recordID, { + fieldNames: Object.keys(fields_view.fields), + fields: fields_view.fields, + fieldAttrs: fields_view.fieldAttrs + }); } var formview = new FormView(fields_view.arch, fields_view.fields, { modelName: self.res_model, diff --git a/addons/web/static/test/fields/relational_fields_tests.js b/addons/web/static/test/fields/relational_fields_tests.js index 531dfc01751..dadb388d65b 100644 --- a/addons/web/static/test/fields/relational_fields_tests.js +++ b/addons/web/static/test/fields/relational_fields_tests.js @@ -20,6 +20,7 @@ QUnit.module('relational_fields', { int_field: {string: "int_field", type: "integer", sortable: true}, qux: {string: "Qux", type: "float", digits: [16,1] }, p: {string: "one2many field", type: "one2many", relation: 'partner', relation_field: 'trululu'}, + turtles: {string: "one2many turtle field", type: "one2many", relation: 'turtle'}, trululu: {string: "Trululu", type: "many2one", relation: 'partner'}, timmy: { string: "pokemon", type: "many2many", relation: 'partner_type'}, product_id: {string: "Product", type: "many2one", relation: 'product'}, @@ -39,6 +40,7 @@ QUnit.module('relational_fields', { int_field: 10, qux: 0.44, p: [], + turtles: [2], timmy: [], trululu: 4, }, { @@ -83,6 +85,36 @@ QUnit.module('relational_fields', { {id: 14, display_name: "silver", color: 5}, ] }, + turtle: { + fields: { + display_name: { string: "Displayed name", type: "char" }, + turtle_foo: {string: "Foo", type: "char", default: "My little Foo Value"}, + turtle_bar: {string: "Bar", type: "boolean", default: true}, + turtle_int: {string: "int", type: "integer", sortable: true, required: true}, + turtle_qux: {string: "Qux", type: "float", digits: [16,1], required: true}, + turtle_trululu: {string: "Trululu", type: "many2one", relation: 'partner', required: true, default: 1}, + product_id: {string: "Product", type: "many2one", relation: 'product', required: true}, + }, + records: [{ + id: 1, + display_name: "leonardo", + turtle_bar: true, + turtle_foo: "yop", + }, { + id: 2, + display_name: "donatello", + turtle_bar: true, + turtle_foo: "blip", + turtle_int: 9, + }, { + id: 3, + display_name: "raphael", + turtle_bar: false, + turtle_foo: "kawa", + turtle_int: 21, + turtle_qux: 9.8, + }], + } }; } }, function () { @@ -1573,42 +1605,44 @@ QUnit.module('relational_fields', { form.destroy(); }); - QUnit.test('one2many with many2many widget', function (assert) { - assert.expect(9); - - this.data.partner.records[0].p = [2]; + QUnit.test('one2many with many2many widget: create', function (assert) { + assert.expect(10); var form = createView({ View: FormView, model: 'partner', data: this.data, arch:'
', archs: { - 'partner,false,list': '