Custom field components in Odoo 18 empower developers to craft specialized user interfaces that align with unique business requirements. This guide demonstrates how to create a custom InputMonth field component, enabling users to select a month and year via a native HTML month picker. By leveraging Odoo 18’s OWL framework, we’ll build a reusable component with clear, step-by-step instructions, including JavaScript, XML, and Python code.
Prerequisites
Before you begin, ensure you have:
- An Odoo 18 instance with a configured development environment.
- Familiarity with JavaScript, OWL 2, XML, and Odoo module development.
- A custom module to house the component.
- Python 3.10 or higher, as required by Odoo 18.
Step 1: Crafting the JavaScript Component
The core of the InputMonth component is defined in a JavaScript file, utilizing Odoo 18’s OWL 2 framework to handle rendering and data interaction.
JavaScript Code :- Create static/src/js/input_month.js:
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { _t } from "@web/core/l10n/translation";
import { useInputField } from "@web/views/fields/input_field_hook";
import { standardFieldProps } from "@web/views/fields/standard_field_props";
import { Component } from "@odoo/owl";
export class InputMonth extends Component {
static template = "your_module_name.InputMonth";
static props = {
...standardFieldProps,
placeholder: { type: String, optional: true },
};
setup() {
useInputField({ getValue: () => this.props.record.data[this.props.name] || "" });
}
}
export const month = {
component: InputMonth,
displayName: _t("Month"),
supportedTypes: ["char"],
extractProps: ({ attrs }) => ({
placeholder: attrs.placeholder,
}),
};
registry.category("fields").add("month", month);
Explanation:
- The InputMonth class extends Component from OWL 2, defining the component’s logic.
- The static template references an XML template for rendering.
- The useInputField hook synchronizes the input with Odoo’s data model.
- The component is registered under the fields category as month, making it available for form views.
- The _t function from @web/core/l10n/translation handles translations, consistent with Odoo 18 conventions.
Step 2: Designing the XML Template
The XML template controls the component’s appearance, supporting both editable and read-only modes.
XML Template :- Create static/src/xml/input_month.xml:
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="your_module_name.InputMonth">
<div class="o_phone_content d-inline-flex w-100">
<t t-if="props.readonly">
<a t-if="props.record.data[props.name]" class="o_form_uri" target="_blank" t-esc="props.record.data[props.name]"/>
</t>
<t t-else="">
<input
class="o_input"
t-att-id="props.id"
type="month"
autocomplete="off"
t-att-placeholder="props.placeholder"
t-ref="input"
/>
</t>
</div>
</t>
</templates>
Explanation:
- The template uses OWL’s <t> tags for conditional rendering.
- In read-only mode (props.readonly), the field displays as a clickable link if a value exists.
- In edit mode, it renders an HTML <input type="month"> for selecting a month and year.
- The t-ref="input" attribute links the input to the useInputField hook.
Step 3: Integrating Assets into the Module
To load the JavaScript and XML files, update the module’s manifest to include them in the appropriate asset bundle.
Manifest Configuration :- In __manifest__.py:
'assets': {
'web.assets_backend': [
'your_module_name/static/src/js/input_month.js',
'your_module_name/static/src/xml/input_month.xml',
],
},
Explanation:
- The web.assets_backend bundle ensures the component loads in backend views (e.g., form views).
Step 4: Applying the Component in a View
Use the custom month widget in a form view to display the InputMonth component.
Form View Example :- In your view XML:
<field name="month_field" widget="month"/>
Explanation:
- The month_field is the model field (e.g., a Char field) where the month value is stored.
- The widget="month" attribute links to the registered month component.
Step 5: Defining the Model Field
Add a field to your model to store the month picker’s value.
Python Model :- In your model file:
from odoo import fields, models
class YourModel(models.Model):
_name = 'your.model'
_description = 'Your Model'
month_field = fields.Char(string='Month')
Explanation:
- The month_field is a Char field, suitable for storing month values (e.g., “2025-06”).
- No Odoo 18-specific changes are needed unless you use advanced ORM features.
Step 6: Testing the Component
- Install or upgrade your module in Odoo 18.
- Navigate to a form view containing the month_field.
- Ensure the field renders as a month picker in edit mode and displays correctly in read-only mode.
- Use the browser’s developer tools to check for JavaScript errors or OWL 2 warnings.
Odoo 18-Specific Notes
- Translation: Odoo 18 uses _t from @web/core/l10n/translation for translations, as you noted, ensuring consistency with prior versions.
- OWL: Odoo 18’s OWL framework is backward-compatible for simple components like this. For advanced use cases, explore useState or t-on for reactivity and event handling.
- Asset Management: The web.assets_backend bundle is standard, but Odoo 18 may introduce new bundles. Check documentation for updates.
- Environment: Ensure Python 3.10+ and verify module dependencies for Odoo 18 compatibility.
Conclusion
Developing a custom InputMonth field component in Odoo 18 is a straightforward way to enhance your application’s UI. By combining OWL flexibility with Odoo’s modular architecture, you can create intuitive components tailored to your needs. This month picker example showcases the process, but the same approach applies to other custom fields. Dive into Odoo 18’s capabilities to build powerful, user-centric interfaces for your business.
To read more about How Create a New Field Component in Odoo 17, refer to our blog How Create a New Field Component in Odoo 17.