Enable Dark Mode!
how-widget-rendering-works-in-odoo-19.jpg
By: Safa KB

How Widget Rendering Works in Odoo 19

Technical Odoo 19 Fields and widgets

In Odoo 19, OWL stands for Odoo Web Library and acts as the frontend library for Odoo. All fields in a form view, cards in kanban view, and components on any other dashboard are rendered using OWL components.

An understanding of OWL rendering makes it easier for us to develop custom widgets. Let’s take a look at an example where we will learn about OWL rendering through the development of a Star Rating Widget.

Demo Model

We begin by creating a basic model called owl.task to experiment with the custom widgets.

# -*- coding: utf-8 -*-
from odoo import models, fields
class OwlTask(models.Model):
   _name = 'owl.task'
   _description = 'OWL Widget Rendering Demo Task'
   name = fields.Char(required=True)
   state = fields.Selection([
       ('new', 'New'),
       ('done', 'Done')
   ])
   priority = fields.Integer(string='Priority')

The priority field will implement our custom OWL widget.

Creating the OWL Widget

OWL Widget is a JavaScript object which extends the Component class.

/** @odoo-module **/
import { Component, useState } from "@odoo/owl";
import { registry } from "@web/core/registry";
import { standardFieldProps } from "@web/views/fields/standard_field_props";
export class StarRatingWidget extends Component {
   static template = "owl_widget_rendering_demo.StarRatingWidget";
   static props = { ...standardFieldProps };
   setup() {
       this.state = useState({
           hoverIndex: -1
       });
       this.stars = [1, 2, 3, 4, 5];
   }
   isFilled(index) {
       const active = this.state.hoverIndex >= 0
           ? this.state.hoverIndex
           : (this.props.value || 0);
       return index <= active;
   }
   onStarClick(index) {
       if (!this.props.readonly) {
           this.props.record.update({
               [this.props.name]: index
           });
       }
   }
   onStarHover(index) {
       this.state.hoverIndex = index;
   }
   onStarLeave() {
       this.state.hoverIndex = -1;
   }
}
registry.category("fields").add("star_rating", {
   component: StarRatingWidget,
   displayName: "Star Rating",
   supportedTypes: ["integer"],
});

Understanding the Rendering Logic

This demo shows a few key aspects of OWL rendering.

1. Reactive Rendering Using useState()

this.state = useState({
   hoverIndex: -1
});

When a variable is assigned to useState(), it becomes reactive. As soon as the value of hoverIndex is changed, OWL will re-render the component.

Example:

this.state.hoverIndex = index;

2. Rendering Multiple Items Using t-foreach

Within the template, stars are generated dynamically using t-foreach.

<t t-foreach="stars" t-as="star" t-key="star">

This loops through:

[1, 2, 3, 4, 5]

and creates five star elements.

Using the t-key property helps identify each star, enabling OWL to easily recycle DOM nodes when re-rendering occurs.

3. Dynamic Class Rendering

<span t-att-class="'owr-star ' + (isFilled(star) ? 'filled' : '')"

The t-att-class directive dynamically adds the CSS class.

If isFilled(star) is true, then the filled class is added, which highlights the star.

This is among the fundamental elements of OWL rendering where the user interface is automatically modified based on component state.

4. Event Handling in OWL

OWL templates support DOM event binding using t-on-*.

t-on-click="() => onStarClick(star)"

When the user clicks a star:

  • onStarClick() executes
  • The field value updates
  • OWL re-renders the widget

Similarly:

t-on-mouseenter="() => onStarHover(star)">

updates the hover state dynamically.

OWL Template

<t t-name="owl_widget_rendering_demo.StarRatingWidget" owl="1">
   <div class="owr-stars" t-on-mouseleave="onStarLeave">
       <t t-foreach="stars" t-as="star" t-key="star">
           <span t-att-class="'owr-star ' + (isFilled(star) ? 'filled' : '')"
                 t-on-click="() => this.onStarClick(star)"
                 t-on-mouseenter="() => this.onStarHover(star)">
               ?
           </span>
       </t>
   </div>
</t>

Registering the Widget

Finally, register the widget inside the fields registry.

registry.category("fields").add("star_rating", {
   component: StarRatingWidget,
   displayName: "Star Rating",
   supportedTypes: ["integer"],
});

Now it can be used in XML views:

<field name="priority" widget="star_rating"/>

Rendering in Odoo 19 with OWL involves reactive state management and Virtual DOM rendering. By using directives such as t-foreach, t-att-class, and t-on-*, you can build very interactive widgets by writing very little code.

The given example demonstrates that OWL will render the user interface whenever there is any change in the state, which makes the widget very responsive and efficient.

To read more about Complete Overview of Widgets in Odoo 19, refer to our blog Complete Overview of Widgets in Odoo 19.


Frequently Asked Questions

What makes the widget self-updating on hover or star clicks?

The widget makes use of useState() to manage state reactively. Every time there's an update such as hoverIndex, the mutation will be detected by OWL and the concerned DOM elements will get re-rendered without reloading the entire page.

What is the significance of using t-key within t-foreach tags?

Using t-key enables each element rendered to have a unique identifier. This helps during rendering to allow OWL compare both old and new Virtual DOM nodes using their unique keys.

Why is widget registration in fields registry necessary?

Registering the widget through: registry.category("fields").add(...) links up the OWL component with Odoo's view system. If this step wasn't taken, it would be impossible to utilize:

If you need any assistance in odoo, we are online, please chat with us.



0
Comments



Leave a comment



whatsapp_icon
location

Calicut

Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635

location

Kochi

Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.

location

Bangalore

Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message