In Odoo, widgets are used to customize the display and behavior of fields in views. A custom widget can be created to display data uniquely, add interactivity, or integrate additional functionality. In this example, we will create a custom widget that displays a popover with order line count and quantity information when clicked.
The JavaScript component defines the behavior and structure of the widget. Odoo 18 uses the Owl framework for building components. Below is the breakdown of the JavaScript code:
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { usePopover } from "@web/core/popover/popover_hook";
import { Component } from "@odoo/owl";
export class orderLineCountPopover extends Component {
setup() {
this.actionService = useService("action");
}
}
orderLineCountPopover.template = "your_module.OrderLineCountPopOver";
export class orderLineCountWidget extends Component {
setup() {
this.popover = usePopover(this.constructor.components.Popover, { position: "top" });
this.calcData = {};
}
showPopup(ev) {
this.popover.open(ev.currentTarget, {
record: this.props.record,
calcData: this.calcData,
});
}
}
orderLineCountWidget.components = { Popover: orderLineCountPopover };
orderLineCountWidget.template = "your_module.orderLineCount";
export const OrderLineCountWidget = {
component: orderLineCountWidget,
};
registry.category("view_widgets").add("order_line_count_widget", OrderLineCountWidget);
- orderLineCountPopover: This is the popover component that displays additional information when the widget is clicked.
- orderLineCountWidget: This is the main widget component. It uses the usePopover hook to display the popover when clicked.
- registry.category("view_widgets").add: Registers the widget in Odoo's view widget registry so it can be used in views.
The XML templates define the structure and appearance of the widget and popover. These templates are linked to the JavaScript components.
<?xml version="1.0" encoding="UTF-8" ?>
<template id="template" xml:space="preserve">
<t t-name="your_module.orderLineCount">
<a t-on-click="showPopup" t-attf-class="fa fa-list"/>
</t>
<t t-name="your_module.OrderLineCountPopOver">
<div>
<table class="table table-borderless table-sm">
<br/>
<tr>
<td><h5>Order line count:</h5></td>
<td>
<h6><span t-out='props.record.data.order_line_count'/></h6>
</td>
</tr>
<tr>
<td><h5>Number of quantity:</h5></td>
<td>
<h6><span t-out='props.record.data.num_qty'/></h6>
</td>
</tr>
</table>
</div>
</t>
</template>
Order line count: | |
Number of quantity: | |
- t-name: Links the template to the JavaScript component.
- t-on-click: Binds the showPopup method to the click event of the icon.
- t-out: Safely renders the value of the field in the template.
The Python model defines the computed fields that provide the data for the widget.
# -*- coding: utf-8 -*-
from odoo import fields, models
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
order_line_count = fields.Integer(string='Order Line Count', compute='compute_line_count', store=True)
num_qty = fields.Integer(string='Number Of Quantity', compute='compute_line_count', store=True)
def compute_line_count(self):
for rec in self:
rec.order_line_count = len(rec.order_line.mapped('id'))
rec.num_qty = sum(rec.order_line.mapped('product_qty'))
- order_line_count: Computes the number of order lines.
- num_qty: Computes the total quantity of products in the order lines.
- compute_line_count: The method that calculates the values for the computed fields.
The XML view definition integrates the widget into the Odoo view.
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="purchase_order_view_tree" model="ir.ui.view">
<field name="name">purchase.order.tree.custom</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_view_tree"/>
<field name="arch" type="xml">
<xpath expr="//list" position="inside">
<field name="order_line_count" column_invisible="1"/>
<field name="num_qty" column_invisible="1"/>
<widget name="order_line_count_widget"/>
</xpath>
</field>
</record>
</odoo>

This is an Odoo Purchase Order tree view with a custom view widget for each row. If we click on the icon,

In the view widget, it shows extra info for each purchase order: Order line count and Number of quantities.
By adhering to this guide, one can develop a custom view widget in Odoo 18 that presents a popover displaying the order line count and quantity information. This methodology is also adaptable for the creation of additional custom widgets.
To read more about How to Create a Widget in Odoo 18 , refer to our blog How to Create a Widget in Odoo 18.