services
inputs
Datetime Picker
Odoo 19 services — Datetime Picker (core)
Live preview
Interactive
Source excerpt
web/static/src/core/datetime/datetimepicker_service.js
import { markRaw, onPatched, onWillRender, reactive, useEffect, useRef } from "@odoo/owl";
import { areDatesEqual, formatDate, formatDateTime, parseDate, parseDateTime } from "../l10n/dates";
import { makePopover } from "../popover/popover_hook";
import { registry } from "../registry";
import { ensureArray, zip, zipWith } from "../utils/arrays";
import { shallowEqual } from "../utils/objects";
import { DateTimePicker } from "./datetime_picker";
import { DateTimePickerPopover } from "./datetime_picker_popover";
/**
* @typedef {luxon["DateTime"]["prototype"]} DateTime
*
* @typedef {import("./datetime_picker").DateTimePickerProps} DateTimePickerProps
* @typedef {import("../popover/popover_hook").PopoverHookReturnType} PopoverHookReturnType
* @typedef {import("../popover/popover_service").PopoverServiceAddOptions} PopoverServiceAddOptions
* @typedef {import("@odoo/owl").Component} Component
* @typedef {ReturnType<typeof import("@odoo/owl").useRef>} OwlRef
*
* @typedef {{
* createPopover?: (component: Component, options: PopoverServiceAddOptions) => PopoverHookReturnType;
* ensureVisibility?: () => boolean;
* format?: string;
* getInputs?: () => HTMLElement[];
* onApply?: (value: DateTimePickerProps["value"]) => any;
* onChange?: (value: DateTimePickerProps["value"]) => any;
* onClose?: () => any;
* pickerProps?: DateTimePickerProps;
* showSeconds?: boolean;
* target: HTMLElement | string;
* useOwlHooks?: boolean;
* }} DateTimePickerServiceParams
*/
/**
* @template {object} T
* @param {T} obj
*/
function markValuesRaw(obj) {
/** @type {T} */
const copy = {};
for (const [key, value] of Object.entries(obj)) {
if (value && typeof value === "object") {
copy[key] = markRaw(value);
} else {
copy[key] = value;
}
}
return copy;
}
/**
* @param {Record<string, any>} props
*/
function stringifyProps(props) {
const copy = {};
for (const [key, value] of Object.entries(props)) {
copy[key] = JSON.stringify(value);
}
return copy;
}
const FOCUS_CLASSNAME = "text-primary";
const formatters = {
date: formatDate,
datetime: formatDateTime,
};
const listenedElements = new WeakSet();
const parsers = {
date: parseDate,
datetime: parseDateTime,
};
export const datetimePickerService = {
dependencies: ["popover"],
start(env, { popover: popoverService }) {
const dateTimePickerList = new Set();
return {
/**
* @param {DateTimePickerServiceParams} [params]
*/
create(params = {}) {
/**
* Wrapper method on the "onApply" callback to only call it when the
* value has changed, and set other internal variables accordingly.
*/
async function apply() {
const { value } = pickerProps;
const stringValue = JSON.stringify(value);
if (
stringValue === lastAppliedStringValue ||
stringValue === stringProps.value
) {
return;
}
lastAppliedStringValue = stringValue;
inputsChanged = ensureArray(value).map(() => false);
await params.onApply?.(value);
stringProps.value = stringValue;
}
function enable() {
for (const [el, value] of zip(
getInputs(),
ensureArray(pickerProps.value),
true
)) {
updateInput(el, value);
if (el && !el.disabled && !el.readOnly && !listenedElements.has(el)) {
listenedElements.add(el);
el.addEventListener("change", onInputChange);
el.addEventListener("click", onInputClick);
el.addEventListener("focus", onInputFocus);
el.addEventListener("keydown", onInputKeydown);
}
}
const calendarIconGroupEl = getInput(0)?.parentElement.querySelector(
Registry / API
- Registry name
datetime_picker- Category
services- Module
web- Slug
datetime-picker- Nav group
inputs