Enable Dark Mode!
how-to-load-js-function-in-menu-item-click-in-odoo-19.jpg
By: Abhinraj R

How to Load JS Function in Menu Item Click in Odoo 19

Technical Odoo 19 Owl

Odoo 19 comes with a more compelling and flexible frontend architecture, based on OWL, which allows developers to design highly interactive features directly inside the backend interface. While Odoo’s Python framework handles core business logic, many modern customizations require JavaScript-driven behavior, especially for dashboards, UI utilities, and dynamic tools. This is a pretty common demand: triggering JavaScript logic upon clicking on a menu item. Odoo does support this through client actions where, instead of loading a traditional view, it would load custom OWL components.

In this blog, we will go through the entire process of creating a menu item that executes some JavaScript code using a client action. The example will illustrate how Python, XML, and OWL interact with each other to deliver seamless functionality to the frontend in Odoo 19.

Step 1: Create a Menu Item

To begin, we need to add a menu item that triggers the JavaScript function when selected. The code below shows how to create this menu item.

/my_js_menu_module/views/action_views.xml
<menuitem
           id="menu_my_js_sub_menu"
           name="Trigger JS Function"
           parent="menu_my_js_root"
           action="action_my_custom_js"
           sequence="10"
       />

For the menu item to display correctly, we need to define a server action or a client action whose ID matches the action referenced in the menu. Odoo provides two ways to load a function from a menu item: using ir.actions.client or ir.actions.server

Step 2: Loading a Function

1 - Using ir.actions.server

While our focus is on JavaScript, it's worth noting that if you intend for a menu click to execute Python logic on the backend, you would use an `ir.actions.server` record instead of `ir.actions.client`. This allows for custom backend operations like data processing or automation.

<record id="action_my_custom_js" model="ir.actions.server">
    <field name="name">Execute Python Logic</field>
    <field name="model_id" ref="your_module.model_name"/>
    <field name="state">code</field>
    <field name="code">
        # Fetch the first 5 customers
        partners = env['res.partner'].search([('customer_rank', '>', 0)], limit=5)
        for partner in partners:
            raise UserError("Customer Name: %s" % partner.name)
    </field>
</record>
  • Name: The display name of the server action (e.g., Execute Python Logic).
  • Model_id: Specifies the model on which the action will run.
  • State: Set to "code" to indicate that this action will execute Python code.
  • Code: The actual Python logic that will be executed when the action is triggered

2 -Using ir.actions.client

These actions don’t open standard Odoo views like forms or lists. Instead, they tell the Odoo web client to load and run a particular JavaScript component. Each client action is identified using a unique tag, which the frontend uses to trigger the correct behavior.

/my_js_menu_module/views/action_views.xml
<?xml version="1.0" encoding="UTF-8"?> 
<odoo> 
   <data>
       <!-- Client Action to load custom JS -->
       <record id="action_my_custom_js" model="ir.actions.client">
           <field name="name">My Custom JS Action</field>
           <field name="tag">my_js_menu_module.my_custom_action</field>
       </record>
<!-- Root Menu and submenu ?
<menuitem
   id="menu_my_js_root"
   name="My JS Menu"
   sequence="10"/>
<!-- Sub Menu Item linked to Client Action ?
<menuitem
   id="menu_my_js_sub_menu"
   name="Trigger JS Function"
   parent="menu_my_js_root"
   action="action_my_custom_js"
   sequence="10"
/>
   </data>
</odoo>
  • The `id` of the client action (`action_my_custom_js`) is referenced by the `action` attribute of the menu item.
  • The `tag` field (`my_js_menu_module.my_custom_action`) must precisely match the key used when registering your JavaScript component.

Step 4: Create the JavaScript OWL Component

This file contains our custom JavaScript logic, encapsulated within an OWL component. The component's `setup()` method is where we can perform initial actions, and we register this component with the Odoo frontend's action registry.

/my_js_menu_module/static/src/js/my_custom_action.js
/** @odoo-module **/
import { Component, useState } from "@odoo/owl";
import { registry } from "@web/core/registry";
class MyCustomAction extends Component {
   setup() {
       this.state = useState({ message: "Hello, Odoo 19!" });
   }
   changeMessage() {
       this.state.message = "JS Function Triggered Successfully!";
   }
}
MyCustomAction.template = "my_js_menu_module.MyCustomAction";
registry.category("actions").add("my_js_menu_module.my_custom_action", MyCustomAction);
  • Here MyCustomAction is our custom owl component
  • Assigns a template to the custom client action by setting MyCustomAction.template = "my_js_menu_module.MyCustomAction";
  • Registers the client action in Odoo’s action registry so it can be called from menus: registry.category("actions").add("my_js_menu_module.my_custom_action", MyCustomAction);
  • Ensures the action is recognized by linking the action name (my_js_menu_module.my_custom_action) with the JavaScript class (MyCustomAction).

Step 5: OWL Template

This QWeb template defines the HTML structure that our `MyCustomAction` OWL component will render when the client action is triggered. It includes a heading, a paragraph, and a button to re-execute our JavaScript function.

<!-- /my_js_menu_module/static/src/xml/my_custom_action.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<templates>
   <t t-name="my_js_menu_module.MyCustomAction">
       <div class="o_my_custom_action p-3">
           <h1>Welcome to My Custom JS Action!</h1>
     <p t-esc="state.message"/>
           <button class="btn btn-primary" t-on-click="changeMessage">
               Click Me
           </button>
       </div>
   </t>
</templates>

Step 6: Add JavaScript to Manifest

Make sure your JavaScript file is properly loaded by adding it to the web.assets_backend section inside your module’s __manifest__.py file.

{
   'name': 'My JS Menu Module',
   'version': '19.0.1.0.0',
   'category': 'Technical',
   'summary': 'Load JS Function via Menu Item Click in Odoo 19',
   'depends': ['base', 'web'],
   'data': [
       'views/action_views.xml',
   ],
   'assets': {
       'web.assets_backend': [
           'my_js_menu_module/static/src/js/my_custom_action.js',
           'my_js_menu_module/static/src/xml/my_custom_action.xml',
       ],
   },
   'installable': True,
   'application': False,
   'auto_install': False,
   'license': 'LGPL-3',
}

By adding these entries, Odoo automatically compiles and serves your JS and XML files, making your client action available from the UI.

Implementing a JavaScript action through a menu click in Odoo 19 is a straightforward process once you understand how client actions, OWL components, and assets work together. By linking your menu item to a custom client action and loading the corresponding JS and XML templates, you can extend the backend with interactive features tailored to your needs. This approach gives developers a clean and modular way to bring dynamic behavior into Odoo’s interface without complicating the backend logic.

To read more about How to Load JS Function in Menu Item Click in Odoo 18, refer to our blog How to Load JS Function in Menu Item Click in Odoo 18.


Frequently Asked Questions

Why must the tag in ir.actions.client match the registry key in JavaScript?

The tag is how Odoo's frontend identifies which OWL component to load. If the tag and registry key don't match exactly, Odoo won't find the component and will throw an error.

What is useState in an OWL component?

useState is a reactive state hook in OWL. When the state value changes, the UI automatically re-renders to reflect the updated value — without manually touching the DOM.

What happens if I forget to add the JS file to web.assets_backend in the manifest?

Odoo won't load your JavaScript file, so the client action will fail with an error saying the action tag is not registered.

When should I use ir.actions.client vs ir.actions.server?

The choice depends on where your logic resides. Use ir.actions.client when you need frontend behavior using JavaScript, such as UI interactions or dashboards. Use ir.actions.server when you want to execute backend logic written in Python, such as data processing or automation tasks.

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
Kakkanchery, 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