Creating OWL Components
Steps
1. Create JavaScript Component (static/src/js/my_component.js)
javascript
/** @odoo-module **/
import { Component, useState, onWillStart } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
export class MyComponent extends Component {
static template = "my_module.MyComponent";
static props = {
title: { type: String, optional: true },
};
setup() {
this.orm = useService("orm");
this.notification = useService("notification");
this.state = useState({
records: [],
loading: true,
});
onWillStart(async () => {
await this.loadData();
});
}
async loadData() {
this.state.loading = true;
try {
this.state.records = await this.orm.searchRead(
"res.partner",
[["is_company", "=", true]],
["name", "email"],
{ limit: 10 }
);
} finally {
this.state.loading = false;
}
}
onRecordClick(record) {
this.notification.add(`Clicked: ${record.name}`, { type: "info" });
}
}
2. Create QWeb Template (static/src/xml/my_component.xml)
xml
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="my_module.MyComponent">
<div class="my-component p-3">
<h3 t-if="props.title" t-esc="props.title"/>
<div t-if="state.loading" class="text-muted">Loading...</div>
<div t-else="">
<div t-foreach="state.records" t-as="record" t-key="record.id"
class="my-component-record p-2 border-bottom"
t-on-click="() => this.onRecordClick(record)">
<strong t-esc="record.name"/>
<span t-if="record.email" class="ms-2 text-muted" t-esc="record.email"/>
</div>
</div>
</div>
</t>
</templates>
3. Add Styles (Optional) (static/src/scss/my_component.scss)
scss
.my-component {
.my-component-record {
cursor: pointer;
&:hover {
background-color: rgba(0, 0, 0, 0.05);
}
}
}
4. Register in Asset Bundle (__manifest__.py)
python
'assets': {
'web.assets_backend': [
'my_module/static/src/js/my_component.js',
'my_module/static/src/xml/my_component.xml',
'my_module/static/src/scss/my_component.scss',
],
},
5. Register as Client Action (Optional)
javascript
// At the end of my_component.js
registry.category("actions").add("my_module.my_action", MyComponent);
xml
<record id="my_component_action" model="ir.actions.client">
<field name="name">My Component</field>
<field name="tag">my_module.my_action</field>
</record>
Checklist
- •
@odoo-modulepragma at the top of JS file - •
static templatematches the QWeb template name - •
static propsdefined for type validation - • Services used via
useService()insetup() - • Template uses
t-keyont-foreachloops - • Assets declared in
__manifest__.py - • Component registered in appropriate registry (if needed)