Enable Dark Mode!
how-widget-events-work-in-odoo-19-js-widgets.jpg
By: Muhammed Fahis V P

How Widget Events Work in Odoo 19 JS Widgets

Technical Odoo 19 Odoo Enterprises Odoo Community

All web applications involve interactions with the user. If the user clicks on a button, selects a record, or updates a field, each of these actions emits an event. Odoo 19's OWL components interact with one another and handle user interactions using those events.

Instead of calling the methods from another component directly, the two components may share information via a callback event. The components can be kept separated and be reusable.

In this blog, we'll see how widget events work in Odoo 19 and how to use them when creating a new interface.

What are widget events in Odoo 19?

Widget events enable one component to announce that something occurred to another component.

Widget events are usually used when:

  • A child component wants to inform the parent component that an event occurred
  • Several components must respond to a user interaction
  • A part of the data must be shared between components
  • A component needs to be able to be reused in any component

Event Flow in Components

In Odoo 19, components follow a parent-child structure. A parent component passes callback methods to its child through props.

Parent Component
    |
    +-- Child Component A
    |
    +-- Child Component B

When a child component calls one of these callbacks, the corresponding method in the parent is executed.

This keeps communication simple and organized.

Setting Up an OWL Component

Every OWL component starts with the following import:

/** @odoo-module **/
import { Component, useState } from "@odoo/owl";

The @odoo-module directive allows Odoo to recognize the file as an ES module.

Sending Events from Child Components

In Odoo 19, child components communicate with their parents using callback functions passed through props.

For example:

this.props.onRecordSelected({
    recordId: 10,
});

The object passed to the callback contains the required data.

Parent Component

The parent component defines the handler and passes it to the child.

/** @odoo-module **/
import { Component, useState } from "@odoo/owl";
import { ChildWidget } from "@my_module/js/child_widget";
export class ParentWidget extends Component {
    static template = "MyModule.ParentWidget";
    static components = { ChildWidget };
    setup() {
        this.state = useState({ logs: [] });
    }
    _onRecordSelected(data) {
        console.log(data.recordId);
    }
}
In the template:
<ChildWidget
    onRecordSelected.bind="_onRecordSelected"
/>

The .bind suffix ensures that the method is executed using the parent component's context.

Creating a Child Component

Suppose we have a button inside a child component. When the button is clicked, the child notifies the parent.

child_widget.js

/** @odoo-module **/
import { Component } from "@odoo/owl";
export class ChildWidget extends Component {
    static template = "MyModule.ChildWidget";
    static props = {
        onRecordSelected: Function,
        onProductChanged: Function,
        onReloadParent: Function,
    };
    _onSelectRecord() {
        this.props.onRecordSelected({
            recordId: 25,
        });
    }
    _onChangeProduct() {
        this.props.onProductChanged({
            productId: 45,
            quantity: 3,
            price: 120,
        });
    }
    _onCreateRecord() {
        this.props.onReloadParent({});
    }
}

Child Template

<t t-name="MyModule.ChildWidget">
    <div>
        <button class="btn btn-primary" t-on-click="_onSelectRecord">
            Select Record
        </button>
        <button class="btn btn-secondary" t-on-click="_onChangeProduct">
            Change Product
        </button>
        <button class="btn btn-success" t-on-click="_onCreateRecord">
            Create Record
        </button>
    </div>
</t>

When a button is clicked:

  1. The corresponding method is executed.
  2. The child component calls the callback.
  3. The parent receives the data.
  4. The parent performs the required action.

Passing Multiple Values

Callbacks can also send multiple values.

_onChangeProduct() {
    this.props.onProductChanged({
        productId: 45,
        quantity: 3,
        price: 120,
    });
}

In the parent component:

_onProductChanged(data) {
    const productId = data.productId;
    const quantity = data.quantity;
    const price = data.price;
}

This makes it easy to transfer related information between components.

DOM Events and Component Events

Both DOM events and component events are used in Odoo 19, but they serve different purposes.

DOM EventsComponent Events
Triggered by browser actionsTriggered between components
Used for user interactionsUsed for component communication
Defined with t-on-click, t-on-change, etc.Implemented using callback props
Example: button clickExample: record selection

Example of DOM events:

<button t-on-click="_onSave">
    Save
</button>
<input t-on-change="_onQuantityChange"/>
Example of component communication:
<ChildWidget
    onProductChanged.bind="_onProductChanged"
/>

Both approaches are often used together.

Refreshing the Parent Component

A child component can notify the parent after creating a record.

Child Component

_createRecord() {
    this.props.onReloadParent({});
}

Parent Component

_onReloadParent() {
    this.reload();
}

This pattern is commonly used in dialogs, dashboards, Kanban views, and custom interfaces.

Registering the Component

To use the component as a client action, register it in the actions registry.

import { registry } from "@web/core/registry";
registry.category("actions").add(
    "my_module_action",
    ParentWidget
);
Then create the client action:
<record id="action_my_widget" model="ir.actions.client">
    <field name="name">My Widget Demo</field>
    <field name="tag">my_module_action</field>
</record>

The value of the tag field must match the key used while registering the component.

Reactive State with useState()

useState() allows components to update the UI automatically whenever data changes.

setup() {
    this.state = useState({
        logs: [],
        recordId: null,
    });
}
_onRecordSelected(data) {
    this.state.recordId = data.recordId;
}

Whenever the state changes, OWL re-renders the template automatically.

Best Practices

Use Meaningful Callback Names

Choose names that clearly describe the action.

static props = {
    onRecordSaved: Function,
    onInvoiceConfirmed: Function,
    onLineRemoved: Function,
    onProductUpdated: Function,
};
Avoid generic names such as:
static props = {
    onEvent: Function,
    onUpdate: Function,
};

Keep Components Independent

Child components should not directly access parent methods. Instead, use callback props.

this.props.onReloadParent({});

This makes the component reusable in different situations.

Declare Props Explicitly

Always define the expected props.

static props = {
    onRecordSelected: Function,
    onProductChanged: Function,
    onReloadParent: Function,
};

Pass Only Required Data

When sending data between components, it is better to pass only the information that the parent component actually needs. Sending unnecessary data increases the amount of information being transferred and can make the code harder to maintain.

For example, if the parent only needs the record ID, you can send just that value:

this.props.onRecordSelected({
    recordId: 15,
});

Instead of sending an entire record object with many unused fields, keep the payload small and focused. This makes the communication between components clearer and easier to manage.

Widget events represent one of the fundamental features of component communication within Odoo 19. The use of callback props allows parent and child components to share information without the burden of forming undesirable dependencies between components. By rendering components as independent entities and only transferring essential data between them, it becomes feasible to engineer more maintainable and reusable interfaces. These event mechanisms will prove helpful while working on custom components, dashboards, dialogs, or Kanban views in Odoo 19.

To read more about How Widget Rendering Works in Odoo 19, refer to our blog How Widget Rendering Works in Odoo 19.


Frequently Asked Questions

What are widget events in Odoo 19?

Widget events are primarily used as an alternative means of communication between OWL components. The events can be utilized by child components to communicate certain events with their parent components. Events like when a button is clicked, a record is selected, or a data set changes could all trigger an event that the parent component listening to would be able to act on.

Does Odoo 19 still support the legacy Widget class?

No. The legacy Widget class has been removed entirely with Odoo 19. All of JavaScript development is carried out through the utilization of OWL components, not legacy Widget components.

How do child components communicate with parent components in Odoo 19?

To achieve child-to-parent communication in Odoo 19, developers will need to implement callback functions. These callbacks are passed as props to the child component and can be called by the child component, allowing data to be transmitted to the parent component which will then act on that information.

What is the meaning of .bind in component templates?

When using callbacks, adding the .bind suffix in component templates will enable the parent component to call the methods in the component using the correct context.

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