Skip to content
Home » Odoo 18 OWL JS Tutorial

Odoo 18 OWL JS Tutorial

  • owl
Odoo 18 OWL JS

Master New OWL 2 Features

Introduction

First, Odoo 18 OWL JS delivers a powerful reactive framework for building dynamic UIs. Furthermore, it streamlines your JavaScript development by cutting boilerplate code significantly. Next, this tutorial will guide you step-by-step through each new feature so you can upgrade your Odoo widgets confidently. Finally, you will see clear code examples and explanations that help you adopt OWL 2 quickly.

source : https://www.pysquad.com/blogs/odoo-18-owl-js-key-improvements-over-odoo-17?utm_source=pocket_saves

Why Upgrade to Odoo 18 OWL JS

First, Odoo 18 OWL JS enhances performance with automatic updates that reflect state changes instantly. Next, it provides new lifecycle hooks that let you run code at precise moments in a component’s life. Moreover, built-in props validation catches errors early and reduces runtime bugs. Consequently, you will write cleaner code with fewer headaches. Finally, dynamic components and slots give you flexible UI patterns that scale as your application grows.

Prerequisites

First, ensure that you run Odoo 18 on your development machine. Next, install Node.js v16+ and Yarn (or npm), because OWL 2 uses modern ES6+ features. Moreover, you will need a working Python environment for Odoo server development. Consequently, you should clone an existing custom module or create a fresh one by running:

# create a new module scaffold  
$ odoo scaffold owl_tutorial addons/  

Finally, you will add OWL components under your module’s static/src folder.

Setting Up Your Odoo 18 OWL JS Environment

First, navigate to your module directory and install JavaScript dependencies:

$ cd addons/owl_tutorial/static/src  
$ yarn init -y   # or npm init -y  
$ yarn add owl @odoo/owl axios  # or npm install owl @odoo/owl axios  

Next, configure your build pipeline by creating a webpack.config.js file:

// webpack.config.js  
const odoo = require('@odoo/webpack-module');  
module.exports = odoo({  
  input: './src/index.js',  
  output: { filename: 'bundle.js' },  
});  

Furthermore, link the bundle in your module’s manifest (__manifest__.py):

'assets': {  
    'web.assets_backend': [  
        'owl_tutorial/static/src/bundle.js',  
    ],  
},

Finally, restart your Odoo server and refresh your app to load the new OWL 2 bundle.

Key OWL 2 Improvements in Odoo 18 OWL JS

Below, you will find detailed examples and explanations for each major enhancement.

1. Reactive State Management

Code Example

// counter.js  
import { Component, reactive, tags, mount } from "@odoo/owl";  
class Counter extends Component {  
  setup() {  
    this.state = reactive({ count: 0 });  
  }  
  increment() {  
    this.state.count++;  
  }  
}  
Counter.template = tags.xml/* xml */`  
  <div>  
    <button t-on-click="increment">Increment</button>  
    <span>Count: <t t-esc="state.count"/></span>  
  </div>`;  
mount(Counter, { target: document.body });  

Explanation

First, you define a reactive object with reactive({ count: 0 }). Next, when you call this.state.count++, OWL 2 updates the DOM automatically. Moreover, you avoid manual this.render() calls and keep your code concise. Consequently, state changes flow ahead without extra work.

2. New Lifecycle Hooks

Code Example

// logger.js  
import { Component, onMounted, onWillStart, onWillUnmount, tags, mount } from "@odoo/owl";  
class Logger extends Component {  
  setup() {  
    onWillStart(() => console.log("Will start"));  
    onMounted(() => console.log("Mounted"));  
    onWillUnmount(() => console.log("Will unmount"));  
  }  
}  
Logger.template = tags.xml`<div>Check console logs</div>`;  
const app = mount(Logger, { target: document.body });  
setTimeout(() => app.destroy(), 5000);  

Explanation

First, onWillStart runs before initial rendering. Next, onMounted fires after the component appears in the DOM. Moreover, onWillUnmount triggers before cleanup. Consequently, you gain precise control over setup and teardown logic.

3. Reactive Arrays and Objects

Code Example

// todo.js  
import { Component, reactive, tags, mount } from "@odoo/owl";  
class Todo extends Component {  
  setup() {  
    this.state = reactive({ items: ["Task 1"] });  
  }  
  addItem() {  
    this.state.items.push(`Task ${this.state.items.length + 1}`);  
  }  
}  
Todo.template = tags.xml`  
  <div>  
    <button t-on-click="addItem">Add Task</button>  
    <ul>  
      <t t-foreach="state.items" t-as="item">  
        <li><t t-esc="item"/></li>  
      </t>  
    </ul>  
  </div>`;  
mount(Todo, { target: document.body });  

Explanation

First, wrapping items in reactive lets OWL detect array mutations. Next, calling .push() re-renders the <ul> list automatically. Moreover, you avoid replacing entire arrays and keep your code efficient.

4. Improved Template Handling

Code Example

<!-- template.xml -->  
<t t-name="MyComponent">  
  <div>  
    <t t-if="props.showMessage">  
      <p><t t-esc="props.message"/></p>  
    </t>  
    <t t-else="">  
      <p>No message available</p>  
    </t>  
  </div>  
</t>  

Explanation

First, OWL 2 compiles templates faster with an improved parser. Next, the t-if and t-else directives execute reliably. Moreover, you write cleaner XML without extra wrappers.

5. Props Validation

Code Example

// greeting.js  
import { Component, tags, mount } from "@odoo/owl";  
class Greeting extends Component {}  
Greeting.props = {  
  name: { type: String, required: true },  
  age:  { type: Number, default: 0 },  
};  
Greeting.template = tags.xml`  
  <div>Hello, <t t-esc="props.name"/>! You are <t t-esc="props.age"/>.</div>`;  
mount(Greeting, { target: document.body, props: { name: "Sam", age: 28 } });  

Explanation

First, OWL throws an error if you omit name or pass a wrong type. Next, default values apply when you skip optional props. Moreover, prop validation reduces runtime bugs significantly.

6. Enhanced Component Slots

Code Example

// card.js  
import { Component, tags, mount } from "@odoo/owl";  
class Card extends Component {}  
Card.template = tags.xml`  
  <div class="card">  
    <header><slot name="header"/></header>  
    <main><slot/></main>  
    <footer><slot name="footer"/></footer>  
  </div>`;  
class Demo extends Component {}  
Demo.components = { Card };  
Demo.template = tags.xml`  
  <Card>  
    <t t-slot="header">Report</t>  
    <p>Main content here</p>  
    <t t-slot="footer">© 2025</t>  
  </Card>`;  
mount(Demo, { target: document.body });  

Explanation

First, you define multiple slots by name. Next, you pass header and footer content dynamically. Moreover, default slot handles main content. Consequently, you build flexible layouts with minimal code.

7. Cleaner Event Binding

Code Example

<t t-name="Clicker">  
  <button t-on-click="() => alert('Clicked!')">Click Me</button>  
</t>  

Explanation

First, OWL replaces verbose syntax with t-on-click. Next, you attach handlers inline or via methods. Moreover, you avoid confusion with v-on: or other frameworks’ syntax.

8. Dynamic Component Support

Code Example

<t t-name="DynamicDemo">  
  <t t-set="cmp" t-value="state.currentComponent"/>  
  <t t-component="cmp"/>  
</t>  
// dynamic.js  
import { Component, reactive, mount } from "@odoo/owl";  
class Greeting extends Component { /* … */ }  
class Farewell extends Component { /* … */ }  
const components = { Greeting, Farewell };  
class DynamicDemo extends Component {  
  setup() {  
    this.state = reactive({ currentComponent: "Greeting" });  
  }  
  toggle() {  
    this.state.currentComponent = this.state.currentComponent === "Greeting" ? "Farewell" : "Greeting";  
  }  
}  
DynamicDemo.components = components;  
DynamicDemo.template = tags.xml`  
  <div>  
    <button t-on-click="toggle">Toggle</button>  
    <t t-component="state.currentComponent"/>  
  </div>`;  
mount(DynamicDemo, { target: document.body });  

Explanation

First, you store component names in state. Next, <t-component> renders the matching class. Moreover, you switch dynamically without rebuilding the whole app.

9. Improved Modern JavaScript Support

Code Example

// datafetch.js  
import { Component, tags, mount } from "@odoo/owl";  
import axios from "axios";  
class DataFetch extends Component {  
  async setup() {  
    const { data } = await axios.get("/api/items");  
    this.state = { items: data.items };  
  }  
}  
DataFetch.template = tags.xml`  
  <ul>  
    <t t-foreach="state.items" t-as="item"><li><t t-esc="item"/></li></t>  
  </ul>`;  
mount(DataFetch, { target: document.body });  

Explanation

First, you use async/await for clarity. Next, destructuring pulls data.items easily. Moreover, ES modules keep your code modular and maintainable.

10. New API for Component Rendering

Code Example

// main.js  
import { mount } from "@odoo/owl";  
import App from "./app.js";  
const app = mount(App, {  
  target: document.getElementById("app"),  
  props: { user: "Admin" },  
});  

Explanation

First, you call mount() once to bootstrap your app. Next, OWL handles rendering and updates internally. Moreover, you avoid manual attachment logic and focus on component design.

11. Simplified Component Unmounting

Code Example

// teardown.js  
import { mount } from "@odoo/owl";  
import App from "./app.js";  
const app = mount(App, { target: "#app" });  
// … later  
app.destroy();  

Explanation

First, destroy() removes event listeners and DOM nodes cleanly. Next, you prevent memory leaks by tearing down components explicitly. Moreover, OWL handles all cleanup—so you don’t need manual code.

12. How PySquad Can Help with Odoo 18 OWL JS

First, PySquad offers migration services from Odoo 17 to Odoo 18, ensuring a smooth transition to OWL 2. Next, PySquad delivers hands-on training so your team adopts reactive patterns effectively. Moreover, PySquad refactors legacy widgets and optimizes your front-end performance. Finally, PySquad provides ongoing support to keep your Odoo installation up to date and bug-free.

Migration Guide: Upgrading from Odoo 17 OWL to Odoo 18 OWL JS

First, audit your existing OWL 1 widgets and identify manual render calls. Next, update lifecycle methods from mounted() to onMounted() and willUnmount() to onWillUnmount(). Moreover, wrap your state objects and arrays in reactive() to leverage automatic updates. Consequently, you will remove redundant this.render() calls. Afterwards, validate props by adding the props static field with type definitions. Finally, test each component in isolation to confirm that UI updates behave correctly.

Best Practices for Odoo 18 OWL JS Development

First, use reactive state sparingly to avoid over-rendering. Next, group related data in a single reactive object. Moreover, add key attributes in t-foreach loops to help OWL track nodes. Consequently, you will improve performance. Additionally, validate props to catch bugs early. Furthermore, destroy components when you no longer need them to free memory. Finally, follow the official Odoo OWL documentation{:target=”_blank”} for API updates.

Troubleshooting Common OWL 2 Issues

State Not Updating

First, verify that you wrapped your data in reactive(). Next, avoid direct mutations on plain objects. Moreover, ensure that you call component methods correctly with t-on-click="methodName".

Lifecycle Hooks Not Firing

First, check that you imported the hooks from @odoo/owl. Next, confirm that setup() runs before you call hooks. Moreover, ensure that you mount your component with mount() instead of a custom renderer.

Template Compilation Errors

First, validate your XML syntax carefully. Next, run your build tool to catch compile-time errors. Moreover, refer to the official docs for directive usage.

Conclusion

First, Odoo 18 OWL JS brings a modern, reactive framework that simplifies front-end development. Next, its new lifecycle hooks, reactive state management, and props validation improve code quality and maintainability. Moreover, dynamic component support and enhanced slots give you great flexibility in building UIs. Consequently, you can deliver richer features with less code and fewer errors. Finally, by following this tutorial and best practices, you will accelerate your Odoo development workflow.

Frequently Asked Questions

What versions of Odoo support OWL 2?

First, OWL 2 arrives in Odoo 18, and earlier versions remain on OWL 1 or older JS frameworks.

Can I use OWL 2 in community versus enterprise?

First, OWL 2 works identically in both editions, because it lives on the front-end.

How do I debug OWL components?

First, use browser dev tools to inspect DOM updates. Next, add console.log statements within lifecycle hooks. Moreover, enable source maps in your build to see original code.

Where can I learn more?

First, visit the Odoo OWL documentation{:target=”_blank”} for in-depth API details.


Discover more from teguhteja.id

Subscribe to get the latest posts sent to your email.

Leave a Reply

WP Twitter Auto Publish Powered By : XYZScripts.com