[FIX] web: MonetaryField: rerender with currency

The MonetaryField can be rendered with or without a currency. The
currency can change during the lifecyle of the widget (e.g.
currency field in the view, whose value is set by an onchange).
More precisely, the widget can be instantiated without currency,
then a change on another field can trigger an onchange which sets
the currency, and our monetary widget is re-rendered with a
currency.

Before this rev., this wasn't supported in edit mode because the
$el's root node was different if there were a currency or not
(it was an input if there were no currency, and a div containing
an input and a span otherwise). This root node being rendered only
once (at the creation of the widget), the widget wasn't re-rendered
correctly if the currency was suddenly set or unset.

This fix makes the widget behave uniformly whether or not there is
a currency, so now it is always a div containing an input (and
optionally a span if there is a currency).
This commit is contained in:
Aaron Bohy
2017-06-27 14:12:31 +02:00
parent 816a3cd2c1
commit 7ea6f653df
2 changed files with 70 additions and 16 deletions
+13 -16
View File
@@ -17,7 +17,6 @@ var dom = require('web.dom');
var Domain = require('web.Domain');
var DomainSelector = require('web.DomainSelector');
var DomainSelectorDialog = require('web.DomainSelectorDialog');
var field_utils = require('web.field_utils');
var framework = require('web.framework');
var session = require('web.session');
var utils = require('web.utils');
@@ -476,15 +475,14 @@ var FieldMonetary = InputField.extend({
this._setCurrency();
if (this.mode === 'edit' && this.currency) {
if (this.mode === 'edit') {
this.tagName = 'div';
this.className += ' o_input';
}
// use the formatFloat function in edit
if (this.mode === 'edit') {
// use the formatFloat function in edit
this.formatType = 'float';
}
this.formatOptions.currency = this.currency;
this.formatOptions.digits = [16, 2];
},
@@ -514,20 +512,19 @@ var FieldMonetary = InputField.extend({
* @private
*/
_renderEdit: function () {
if (!this.currency) {
this._super.apply(this, arguments);
return;
}
this.$el.empty();
// Prepare and add the input
this._prepareInput().appendTo(this.$el);
// prepare and add the currency symbol
var $currencySymbol = $('<span>', {text: this.currency.symbol});
if (this.currency.position === "after") {
this.$el.append($currencySymbol);
} else {
this.$el.prepend($currencySymbol);
if (this.currency) {
// Prepare and add the currency symbol
var $currencySymbol = $('<span>', {text: this.currency.symbol});
if (this.currency.position === "after") {
this.$el.append($currencySymbol);
} else {
this.$el.prepend($currencySymbol);
}
}
},
/**
@@ -1973,6 +1973,63 @@ QUnit.module('basic_fields', {
form.destroy();
});
QUnit.test('monetary field with currency set by an onchange', function (assert) {
// this test ensures that the monetary field can be re-rendered with and
// without currency (which can happen as the currency can be set by an
// onchange)
assert.expect(8);
this.data.partner.onchanges = {
int_field: function (obj) {
obj.currency_id = obj.int_field ? 2 : null;
},
};
var list = createView({
View: ListView,
model: 'partner',
data: this.data,
arch: '<tree editable="top">' +
'<field name="int_field"/>' +
'<field name="qux" widget="monetary"/>' +
'<field name="currency_id" invisible="1"/>' +
'</tree>',
session: {
currencies: _.indexBy(this.data.currency.records, 'id'),
},
});
list.$buttons.find('.o_list_button_add').click();
assert.strictEqual(list.$('div.o_field_widget[name=qux] input').length, 1,
"monetary field should have been rendered correctly (without currency)");
assert.strictEqual(list.$('.o_field_widget[name=qux] span').length, 0,
"monetary field should have been rendered correctly (without currency)");
// set a value for int_field -> should set the currency and re-render qux
list.$('.o_field_widget[name=int_field]').click().val('7').trigger('input');
assert.strictEqual(list.$('div.o_field_widget[name=qux] input').length, 1,
"monetary field should have been re-rendered correctly (with currency)");
assert.strictEqual(list.$('.o_field_widget[name=qux] span:contains(€)').length, 1,
"monetary field should have been re-rendered correctly (with currency)");
var $quxInput = list.$('.o_field_widget[name=qux] input');
$quxInput.click(); // check that the field is focusable
assert.strictEqual(document.activeElement, $quxInput[0],
"focus should be on the qux field's input");
// unset the value of int_field -> should unset the currency and re-render qux
list.$('.o_field_widget[name=int_field]').click().val('0').trigger('input');
$quxInput = list.$('div.o_field_widget[name=qux] input');
assert.strictEqual($quxInput.length, 1,
"monetary field should have been re-rendered correctly (without currency)");
assert.strictEqual(list.$('.o_field_widget[name=qux] span').length, 0,
"monetary field should have been re-rendered correctly (without currency)");
$quxInput.click(); // check that the field is still focusable
assert.strictEqual(document.activeElement, $quxInput[0],
"focus should be on the qux field's input");
list.destroy();
});
QUnit.module('FieldInteger');
QUnit.test('integer field when unset', function (assert) {