Skip to Content
OWL data_display

Search Bar

Odoo 19 OWL component — Search Bar (search)

Live preview Interactive
Source excerpt web/static/src/search/search_bar/search_bar.js
import { Domain } from "@web/core/domain";
import { serializeDate, serializeDateTime } from "@web/core/l10n/dates";
import { registry } from "@web/core/registry";
import { KeepLast } from "@web/core/utils/concurrency";
import { useAutofocus, useBus, useChildRef, useService } from "@web/core/utils/hooks";
import { DomainSelectorDialog } from "@web/core/domain_selector_dialog/domain_selector_dialog";
import { fuzzyTest } from "@web/core/utils/search";
import { _t } from "@web/core/l10n/translation";
import { SearchBarMenu } from "../search_bar_menu/search_bar_menu";
import { Component, status, useRef, useState } from "@odoo/owl";
import { useDropdownState } from "@web/core/dropdown/dropdown_hooks";
import { hasTouch } from "@web/core/browser/feature_detection";
import { Dropdown } from "@web/core/dropdown/dropdown";
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { useNavigation } from "@web/core/navigation/navigation";

const parsers = registry.category("parsers");

const parseValue = (value, fieldType) => {
    const parser = parsers.contains(fieldType) ? parsers.get(fieldType) : (str) => str;
    switch (fieldType) {
        case "date": {
            return serializeDate(parser(value));
        }
        case "datetime": {
            return serializeDateTime(parser(value));
        }
        case "many2one": {
            return value;
        }
        default: {
            return parser(value);
        }
    }
};

const CHAR_FIELDS = ["char", "html", "many2many", "many2one", "one2many", "text", "properties"];
const FOLDABLE_TYPES = ["properties", "many2one", "many2many"];

let nextItemId = 1;
const SUB_ITEMS_DEFAULT_LIMIT = 8;

export const DROPDOWN_CLOSE_DELAY = 10;

export class SearchBar extends Component {
    static template = "web.SearchBar";
    static components = {
        SearchBarMenu,
        Dropdown,
        DropdownItem,
    };
    static props = {
        autofocus: { type: Boolean, optional: true },
        slots: {
            type: Object,
            optional: true,
            shape: {
                default: { optional: true },
                "search-bar-additional-menu": { optional: true },
            },
        },
        toggler: {
            type: Object,
            optional: true,
        },
    };
    static defaultProps = {
        autofocus: true,
    };

    setup() {
        this.dialogService = useService("dialog");
        this.fields = this.env.searchModel.searchViewFields;
        this.searchItemsFields = this.env.searchModel.getSearchItems((f) => f.type === "field");
        this.root = useRef("root");
        this.ui = useService("ui");

        this.visibilityState = useState(this.props.toggler?.state || { showSearchBar: true });

        // core state
        this.state = useState({
            expanded: [],
            query: "",
            subItemsLimits: {},
        });

        // derived state
        this.items = useState([]);
        this.subItems = {};

        this.facetContainerRef = useRef("facetContainerRef");
        this.menuRef = useChildRef();
        this.setupFacetNavigation();
        this.inputDropdownState = useDropdownState();
        this.inputDropdownNavOptions = this.getDropdownNavigation();

        this.searchBarDropdownState = useDropdownState();

        this.orm = useService("orm");

        this.keepLast = new KeepLast();

        this.inputRef =
            this.env.config.disableSearchBarAutofocus || !this.props.autofocus
                ? useRef("autofocus")
                : useAutofocus({ mobile: this.ui.isSmall }); // only force the focus on touch devices on small screens

        useBus(this.env.searchModel, "focus-search", () => {
            this.inputRef.el.focus();
        });

        useBus(this.env.searchModel, "update", this.render);
    }

    /**
     * @param {number} id
     * @param {Object}
     */
    getSearchItem(id) {
        return this.env.searchModel.searchItems[id];
Registry / API
Registry name
SearchBar
Category
Module
web
Slug
search-bar
Nav group
data_display