Skip to Content
fields forms

Domain

Odoo 19 fields — Domain (views)

Live preview Interactive
Source excerpt web/static/src/views/fields/domain/domain_field.js
import { Component, useState } from "@odoo/owl";
import { Domain, InvalidDomainError } from "@web/core/domain";
import { DomainSelector } from "@web/core/domain_selector/domain_selector";
import { useGetDefaultLeafDomain } from "@web/core/domain_selector/utils";
import { DomainSelectorDialog } from "@web/core/domain_selector_dialog/domain_selector_dialog";
import { _t } from "@web/core/l10n/translation";
import { rpc } from "@web/core/network/rpc";
import { EvaluationError } from "@web/core/py_js/py_builtin";
import { registry } from "@web/core/registry";
import { domainContainsExpressions } from "@web/core/tree_editor/domain_contains_expressions";
import { useBus, useOwnedDialogs, useService } from "@web/core/utils/hooks";
import { useRecordObserver } from "@web/model/relational_model/utils";
import { SelectCreateDialog } from "@web/views/view_dialogs/select_create_dialog";
import { standardFieldProps } from "../standard_field_props";

export class DomainField extends Component {
    static template = "web.DomainField";
    static components = {
        DomainSelector,
    };
    static props = {
        ...standardFieldProps,
        context: { type: Object, optional: true },
        editInDialog: { type: Boolean, optional: true },
        resModel: { type: String, optional: true },
        isFoldable: { type: Boolean, optional: true },
        countLimit: { type: Number, optional: true },
        allowExpressions: { type: Boolean, optional: true },
    };
    static defaultProps = {
        editInDialog: false,
        isFoldable: false,
        countLimit: 10000,
        allowExpressions: false,
    };

    setup() {
        this.orm = useService("orm");
        this.notification = useService("notification");
        this.treeProcessor = useService("tree_processor");
        this.getDefaultLeafDomain = useGetDefaultLeafDomain();
        this.addDialog = useOwnedDialogs();

        this.state = useState({
            isValid: null,
            recordCount: null,
            hasLimitedCount: null,
            folded: this.props.isFoldable,
            facets: [],
        });

        this.debugDomain = null;
        useRecordObserver(async (record, nextProps) => {
            nextProps = { ...nextProps, record };
            if (this.debugDomain && this.props.readonly !== nextProps.readonly) {
                this.debugDomain = null;
            }
            if (this.debugDomain) {
                this.state.isValid = await this.quickValidityCheck(nextProps);
                if (!this.state.isValid) {
                    this.state.recordCount = 0;
                    nextProps.record.setInvalidField(nextProps.name);
                }
            } else {
                this.checkProps(nextProps); // not awaited
            }
            if (nextProps.isFoldable) {
                this.loadFacets(nextProps);
            }
        });

        useBus(this.props.record.model.bus, "NEED_LOCAL_CHANGES", async (ev) => {
            if (this.debugDomain) {
                const props = this.props;
                const handleChanges = async () => {
                    await props.record.update({ [props.name]: this.debugDomain });
                    const isValid = await this.quickValidityCheck(props);
                    if (isValid) {
                        this.debugDomain = null; // will allow the count to be loaded if needed
                    } else {
                        this.state.isValid = false;
                        this.state.recordCount = 0;
                        props.record.setInvalidField(props.name);
                    }
                };
                ev.detail.proms.push(handleChanges());
            }
        });
    }

    allowExpressions(props) {
        return props.allowExpressions;
    }

    getContext(props = this.props) {
        return props.context;
    }

    getDomain(props = this.props) {
        return props.record.data[props.name] || "[]";
    }

    getEvaluatedDomain(props = this.props) {
        const domainStringRepr = this.getDomain(props);
        const evalContext = this.getContext(props);
        if (domainContainsExpressions(domainStringRepr)) {
            const allowExpressions = this.allowExpressions(props);
            if (domainStringRepr !== this.lastDomainChecked) {
                this.lastDomainChecked = domainStringRepr;
                this.notification.add(
                    allowExpressions
                        ? _t("The domain involves non-literals. Their evaluation might fail.")
                        : _t("The domain should not involve non-literals")
                );
            }
            if (!allowExpressions) {
                return { isInvalid: true };
            }
        }
        try {
Registry / API
Registry name
domain
Category
fields
Module
web
Slug
domain
Nav group
forms