+
Web Domain Field
+
+
+

+
When you define a view you can specify on the relational fields a domain
+attribute. This attribute is evaluated as filter to apply when displaying
+existing records for selection.
+
Table of contents
+
+
+
+
When you define a view you can specify on the relational fields a domain
+attribute. This attribute is evaluated as filter to apply when displaying
+existing records for selection.
+
+<field name="product_id" domain="[('type','=','product')]"/>
+
+
The value provided for the domain attribute must be a string representing a
+valid Odoo domain. This string is evaluated on the client side in a
+restricted context where we can reference as right operand the values of
+fields present into the form and a limited set of functions.
+
In this context it’s hard to build complex domain and we are facing to some
+limitations as:
+
+
+- The syntax to include in your domain a criteria involving values from a
+x2many field is complex.
+- The right side of domain in case of x2many can involve huge amount of ids
+(performance problem).
+- Domains computed by an onchange on an other field are not recomputed when
+you modify the form and don’t modify the field triggering the onchange.
+- It’s not possible to extend an existing domain. You must completely redefine
+the domain in your specialized addon
+- etc…
+
+
+
In order to mitigate these limitations this new addon allows you to use the
+value of a field as domain of an other field in the xml definition of your
+view.
+
+<field name="product_id_domain" invisible="1"/>
+<field name="product_id" domain="product_id_domain"/>
+
+
The field used as domain must provide the domain as a JSON encoded string.
+
+product_id_domain = fields.Char(
+ compute="_compute_product_id_domain",
+ readonly=True,
+ store=False,
+)
+
+@api.multi
+@api.depends('name')
+def _compute_product_id_domain(self):
+ for rec in self:
+ rec.product_id_domain = json.dumps(
+ [('type', '=', 'product'), ('name', 'like', rec.name)]
+ )
+
+
+
+
+
Bugs are tracked on GitHub Issues.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed
+feedback.
+
Do not contact contributors directly about support or help with technical issues.
+
+
+
+
+
+
+
+
This module is maintained by the OCA.
+

+
OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
This module is part of the OCA/web project on GitHub.
+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
+
+
+
+
+
diff --git a/web_domain_field/static/lib/js/pyeval.js b/web_domain_field/static/lib/js/pyeval.js
new file mode 100644
index 000000000..6f2b9f61b
--- /dev/null
+++ b/web_domain_field/static/lib/js/pyeval.js
@@ -0,0 +1,212 @@
+odoo.define('web.domain_field', function (require) {
+ "use strict";
+
+ var py_utils = require('web.py_utils');
+ var session = require('web.session');
+
+
+ var original_pyeval = py_utils.eval;
+ var py = window.py;
+
+ /** Copied from py_utils and not modified but required since not publicly
+ exposed by web.py_utils**/
+
+ // recursively wraps JS objects passed into the context to attributedicts
+ // which jsonify back to JS objects
+ function wrap(value) {
+ if (value === null) { return py.None; }
+
+ switch (typeof value) {
+ case 'undefined': throw new Error("No conversion for undefined");
+ case 'boolean': return py.bool.fromJSON(value);
+ case 'number': return py.float.fromJSON(value);
+ case 'string': return py.str.fromJSON(value);
+ }
+
+ switch(value.constructor) {
+ case Object: return wrapping_dict.fromJSON(value);
+ case Array: return wrapping_list.fromJSON(value);
+ }
+
+ throw new Error("ValueError: unable to wrap " + value);
+ }
+
+ var wrapping_dict = py.type('wrapping_dict', null, {
+ __init__: function () {
+ this._store = {};
+ },
+ __getitem__: function (key) {
+ var k = key.toJSON();
+ if (!(k in this._store)) {
+ throw new Error("KeyError: '" + k + "'");
+ }
+ return wrap(this._store[k]);
+ },
+ __getattr__: function (key) {
+ return this.__getitem__(py.str.fromJSON(key));
+ },
+ __len__: function () {
+ return Object.keys(this._store).length;
+ },
+ __nonzero__: function () {
+ return py.PY_size(this) > 0 ? py.True : py.False;
+ },
+ get: function () {
+ var args = py.PY_parseArgs(arguments, ['k', ['d', py.None]]);
+
+ if (!(args.k.toJSON() in this._store)) { return args.d; }
+ return this.__getitem__(args.k);
+ },
+ fromJSON: function (d) {
+ var instance = py.PY_call(wrapping_dict);
+ instance._store = d;
+ return instance;
+ },
+ toJSON: function () {
+ return this._store;
+ },
+ });
+
+ var wrapping_list = py.type('wrapping_list', null, {
+ __init__: function () {
+ this._store = [];
+ },
+ __getitem__: function (index) {
+ return wrap(this._store[index.toJSON()]);
+ },
+ __len__: function () {
+ return this._store.length;
+ },
+ __nonzero__: function () {
+ return py.PY_size(this) > 0 ? py.True : py.False;
+ },
+ fromJSON: function (ar) {
+ var instance = py.PY_call(wrapping_list);
+ instance._store = ar;
+ return instance;
+ },
+ toJSON: function () {
+ return this._store;
+ },
+ });
+
+ function wrap_context(context) {
+ for (var k in context) {
+ if (!context.hasOwnProperty(k)) { continue; }
+ var val = context[k];
+ // Don't add a test case like ``val === undefined``
+ // this is intended to prevent letting crap pass
+ // on the context without even knowing it.
+ // If you face an issue from here, try to sanitize
+ // the context upstream instead
+ if (val === null) { continue; }
+ if (val.constructor === Array) {
+ context[k] = wrapping_list.fromJSON(val);
+ } else if (val.constructor === Object
+ && !py.PY_isInstance(val, py.object)) {
+ context[k] = wrapping_dict.fromJSON(val);
+ }
+ }
+ return context;
+ }
+
+ function ensure_evaluated(args, kwargs) {
+ for (var i=0; i