Assets Management
How to load templates?
How to write odoo-compatible code?
Owl QWeb
Renderer
Old QWeb Engine
Communication with events
Widget
In Widgets:
● events bubble up widget tree
● generated with trigger_up
● caught with custom_events
● use underscores: “something_happened”
In Components:
● events bubble up DOM tree
● generated with trigger
● caught with t-on- directive
● use dash: “something-happened”
across boundaries
Component
Widget
From imperative
to declarative
Widgets are instantiated/updated
manually
Components are instantiated/updated by
Owl
Lifecycle remapping
across boundaries
Widgets
on_attach_callback
on_detach_callback
Components
mounted
willUnmount
JS code style
● No static class fields
● No ultra modern ES features
● No inline template
class MyComponent extends Component {
static template = xml`<div>my template</div>`;
static components = { SubComponent };
...
}
class MyComponent extends Component {
...
}
MyComponent.template =
'myModule.MyComponent';
MyComponent.components = {
SubComponent
};
Owl templates
Add a special attribute: owl=”1” for owl components
<t t-name="AddToGoogleSpreadsheetMenu" owl="1">
<li class="o_menu_item o_add_to_spreadsheet" role="menuitem">
<a class="dropdown-item" href="#"
t-on-click.prevent="_onAddToSpreadsheet">
Add to Google Spreadsheet
</a>
</li>
</t>
View widgets in Owl
<field name="payments_widget" widget="payment"/>
Adding owl field widgets in
views
const AbstractField = require('web.AbstractFieldOwl);
class FieldBadge extends AbstractField {
_getClassFromDecoration(decoration) {
return `bg-${decoration.split('-')[1]}-light`;
}
}
FieldBadge.description = _lt("Badge");
FieldBadge.supportedFieldTypes = ['selection',
'many2one', 'char'];
FieldBadge.template = 'web.FieldBadge';
const registry = require('web.field_registry_owl');
registry
.add('badge', FieldBadge);
<field name="state" widget="badge"/>
It works for: form/list/kanban views
➔ Subclass AbstractFieldOwl (exported in
‘web.AbstractFieldOwl’)
➔ Register it in ‘web.field_registry_owl’
➔ Don’t forget to add widget=... in the arch
What you (might) need to know:
AbstractField API
(web.AbstractFieldOwl)
- field
- isEmpty
- ...
Odoo Env (web.env)
- services
- _t
- bus
- ...
Owl components in Odoo
● Component/Component
● Component/Widget
● Widget/Component
3 kinds of boundaries
1. Component/Component
<t t-name="myModule.AddMyComponent"
t-inherit="web.SomeTemplate"
t-inherit-mode="extension"
owl="1">
<xpath expr="//div[@class='abc']"
position="inside">
<MyComponent mode="’readonly’" />
</xpath>
</t>
class MyComponent extends Component {
...
}
// register the new component as a sub component for
the parent
ParentComponent.components.MyComponent = MyComponent
Standard owl development.
➔ XPath the parent template to add a tag
<MyComponent/> where needed (it
works!!!)
➔ Add MyComponent to parent static
components key
Owl Compatibility Helpers
Component inside Widget Widget inside Component
web.OwlCompatibility
Owl Component
ComponentAdapter
Some Widget
SomeWidget +
WidgetAdapterMixin
ComponentWrapper
Owl Component
2. Component inside Widget
➔ Client action (Hello world)
const AbstractAction =
require('web.AbstractAction');
const { actionRegistry } = require('web.core');
const { ComponentWrapper, WidgetAdapterMixin} =
require('web.OwlCompatibility');
const { Component, tags } = owl;
class HelloWorld extends Component {}
HelloWorld.template = tags.xml`<div>Hello
World!</div>`;
const ClientAction =
AbstractAction.extend(WidgetAdapterMixin, {
start() {
const component =
new ComponentWrapper(this, HelloWorld);
return component.mount(
this.el.querySelector('.o_content')
);
},
});
actionRegistry.add('client_action',
ClientAction);
3. Widget inside Component
with ComponentAdapter
const MyWidget = Widget.extend({
start: function () {
this.$el.text('Hello World!');
}
});
class Parent extends Component {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
}
}
Parent.template = xml`
<div>
<ComponentAdapter
Component="MyWidget"/>
</div>`;
Parent.components = { ComponentAdapter };
Thank You

Developing New Widgets for your Views in Owl

  • 2.
    Assets Management How toload templates? How to write odoo-compatible code? Owl QWeb Renderer Old QWeb Engine
  • 3.
    Communication with events Widget InWidgets: ● events bubble up widget tree ● generated with trigger_up ● caught with custom_events ● use underscores: “something_happened” In Components: ● events bubble up DOM tree ● generated with trigger ● caught with t-on- directive ● use dash: “something-happened” across boundaries Component Widget
  • 4.
    From imperative to declarative Widgetsare instantiated/updated manually Components are instantiated/updated by Owl
  • 5.
  • 6.
    JS code style ●No static class fields ● No ultra modern ES features ● No inline template class MyComponent extends Component { static template = xml`<div>my template</div>`; static components = { SubComponent }; ... } class MyComponent extends Component { ... } MyComponent.template = 'myModule.MyComponent'; MyComponent.components = { SubComponent };
  • 7.
    Owl templates Add aspecial attribute: owl=”1” for owl components <t t-name="AddToGoogleSpreadsheetMenu" owl="1"> <li class="o_menu_item o_add_to_spreadsheet" role="menuitem"> <a class="dropdown-item" href="#" t-on-click.prevent="_onAddToSpreadsheet"> Add to Google Spreadsheet </a> </li> </t>
  • 8.
    View widgets inOwl <field name="payments_widget" widget="payment"/>
  • 9.
    Adding owl fieldwidgets in views const AbstractField = require('web.AbstractFieldOwl); class FieldBadge extends AbstractField { _getClassFromDecoration(decoration) { return `bg-${decoration.split('-')[1]}-light`; } } FieldBadge.description = _lt("Badge"); FieldBadge.supportedFieldTypes = ['selection', 'many2one', 'char']; FieldBadge.template = 'web.FieldBadge'; const registry = require('web.field_registry_owl'); registry .add('badge', FieldBadge); <field name="state" widget="badge"/> It works for: form/list/kanban views ➔ Subclass AbstractFieldOwl (exported in ‘web.AbstractFieldOwl’) ➔ Register it in ‘web.field_registry_owl’ ➔ Don’t forget to add widget=... in the arch
  • 10.
    What you (might)need to know: AbstractField API (web.AbstractFieldOwl) - field - isEmpty - ... Odoo Env (web.env) - services - _t - bus - ...
  • 11.
    Owl components inOdoo ● Component/Component ● Component/Widget ● Widget/Component 3 kinds of boundaries
  • 12.
    1. Component/Component <t t-name="myModule.AddMyComponent" t-inherit="web.SomeTemplate" t-inherit-mode="extension" owl="1"> <xpathexpr="//div[@class='abc']" position="inside"> <MyComponent mode="’readonly’" /> </xpath> </t> class MyComponent extends Component { ... } // register the new component as a sub component for the parent ParentComponent.components.MyComponent = MyComponent Standard owl development. ➔ XPath the parent template to add a tag <MyComponent/> where needed (it works!!!) ➔ Add MyComponent to parent static components key
  • 13.
    Owl Compatibility Helpers Componentinside Widget Widget inside Component web.OwlCompatibility Owl Component ComponentAdapter Some Widget SomeWidget + WidgetAdapterMixin ComponentWrapper Owl Component
  • 14.
    2. Component insideWidget ➔ Client action (Hello world) const AbstractAction = require('web.AbstractAction'); const { actionRegistry } = require('web.core'); const { ComponentWrapper, WidgetAdapterMixin} = require('web.OwlCompatibility'); const { Component, tags } = owl; class HelloWorld extends Component {} HelloWorld.template = tags.xml`<div>Hello World!</div>`; const ClientAction = AbstractAction.extend(WidgetAdapterMixin, { start() { const component = new ComponentWrapper(this, HelloWorld); return component.mount( this.el.querySelector('.o_content') ); }, }); actionRegistry.add('client_action', ClientAction);
  • 15.
    3. Widget insideComponent with ComponentAdapter const MyWidget = Widget.extend({ start: function () { this.$el.text('Hello World!'); } }); class Parent extends Component { constructor() { super(...arguments); this.MyWidget = MyWidget; } } Parent.template = xml` <div> <ComponentAdapter Component="MyWidget"/> </div>`; Parent.components = { ComponentAdapter };
  • 16.

Editor's Notes

  • #7 let’s talk about the odoo ecosystem in general