SlideShare ist ein Scribd-Unternehmen logo
1 von 41
Owl JS
Framework
github.com/odoo/owl
Part 1
Why Owl?
1. Based on XML templates (QWeb)
2. JIT template compilation
3. Easy to integrate in Odoo assets
pipeline
1. Based on XML templates (QWeb)
2. JIT template compilation
3. Easy to integrate in Odoo assets
pipeline
1. Based on XML templates (QWeb)
2. JIT template compilation
3. Easy to integrate in Odoo assets
pipeline
Part 2
Owl design principles
Small(ish)/Low level
framework
about 21 kb (minified/gzipped)
Modern UI toolset
● components
● hooks
● slots
● store
● ...
Strong
concurrency
management
async by default!
A
B C
D E F
Part 3
Let’s build a to-do list
1. Setting up the projecthooks, slots, store and more
hooks, slots, store and more
github.com/ged-odoo/owl-todolist
2. Adding the first
component
const { Component } = owl;
const { xml } = owl.tags;
const { whenReady } = owl.utils;
// Owl Components
class App extends Component {
static template = xml`<div>todo app</div>`;
}
// Setup code
function setup() {
const app = new App();
app.mount(document.body);
}
whenReady(setup);
➔ Components are class, inherit from
Component
➔ An Owl application is a (dynamic) tree
of components, with a root
➔ It is mounted with the mount method
➔ The mount operation completes
when all the sub component tree (if
any) are ready
➔ Templates are inlined here
3. Displaying tasks
➔ Always useful to add demo data
➔ Template is standard QWeb
➔ qweb evaluation context =
component instance
➔ Notice the t-key directive!
const TASKS = [
{
id: 1,
title: "buy milk",
isCompleted: true,
},
{
id: 2,
title: "clean house",
isCompleted: false,
},
];
class App extends Component {
static template = xml`
<div class="task-list">
<t t-foreach="tasks" t-as="task" t-key="task.id">
<div class="task">
<input type="checkbox"
t-att-checked="task.isCompleted"/>
<span><t t-esc="task.title"/></span>
</div>
</t>
</div>`;
tasks = TASKS;
}
4. Style .task-list {
width: 300px;
margin: 50px auto;
background: aliceblue;
padding: 10px;
}
.task {
font-size: 18px;
color: #111111;
}
.task.done {
opacity: 0.7;
}
<div
class="task"
t-att-class="task.isCompleted ? 'done' : ''">
➔ class and t-att-class attributes
can be combined
app.css
Template:
5. Extracting task as a
subcomponent
➔ Most UI are divided into sub
components
➔ Components are described by xml
elements with a capital first letter
➔ Components attributes are given to
actual sub component instance
(props)
const TASK_TEMPLATE = xml`
<div class="task"
t-att-class="props.task.isCompleted ? 'done':''">
<input type="checkbox"
t-att-checked="props.task.isCompleted"/>
<span><t t-esc="props.task.title"/></span>
</div>`;
class Task extends Component {
static template = TASK_TEMPLATE;
}
const APP_TEMPLATE = xml`
<div class="task-list">
<t t-foreach="tasks" t-as="task" t-key="task.id">
<Task task="task"/>
</t>
</div>`;
class App extends Component {
static template = APP_TEMPLATE;
static components = { Task };
tasks = TASKS;
}
UI as a tree of components
Root State
A B C
State
State
Props
D EProps
State
Props
State
class App extends Component {
tasks = TASKS;
...
}
➔ Owned by a component
➔ May be reactive or not
➔ Only owner can update it
➔ Can give reference to other
components (as props)
<div class="task-list">
<t t-foreach="tasks" t-as="task" t-key="task.id">
<Task task="task"/>
</t>
</div>
Props
➔ Can be accessed in this.props
➔ Owned by someone else
➔ Props cannot be updated by
child component
6. Adding tasks
<div class="todo-app">
<input
placeholder="Enter a new task"
t-on-keyup="addTask"/>
<div class="task-list">
...
</div>
</div>
➔ Can add event handler with t-on-
directive
➔ Handler receive event as first
argument
➔ Handler need to be a function in the
rendering context (the component
instance)
addTask(ev) {
// 13 is keycode for ENTER
if (ev.keyCode === 13) {
const title =
ev.target.value.trim();
ev.target.value = "";
console.log('adding task', title);
// todo
}
}
6. Adding tasks
<input
placeholder="Enter a new task"
t-on-keyup="addTask"
t-ref="add-input"/>
➔ Get reference with t-ref directive
➔ Can use mounted lifecycle method
➔ UseRef is our first hook
const { useRef } = owl.hooks;
class App extends Component {
inputRef = useRef("add-input");
mounted() {
this.inputRef.el.focus();
}
...
}
Components Lifecycle
willPatch patched willUnmountconstructor willStart* mounted willUpdateProps*
6. Adding tasks
class App extends Component {
...
nextId = 1;
tasks = [];
...
addTask(ev) {
// 13 is keycode for ENTER
if (ev.keyCode === 13) {
const title =
ev.target.value.trim();
ev.target.value = "";
if (title) {
const newTask = {
id: this.nextId++,
title: title,
isCompleted: false,
};
this.tasks.push(newTask);
}
}
}
}
➔ Generate some id number
➔ Add the task info to the task list
But… It does not work!
We need reactivity
Important hook: useState
6. Adding tasks
// on top of the file
const { useRef, useState } = owl.hooks;
class App extends Component {
tasks = useState([]);
...
}
➔ Make the state reactive with
useState hook
➔ It works with arrays and objects
(even nested)
7. Toggling tasks
<input
type="checkbox"
t-att-
checked="props.task.isCompleted"
t-on-click="toggleTask"/>
class Task extends Component {
static template = TASK_TEMPLATE;
toggleTask() {
// ???
}
}
➔ Task component cannot change a
task
➔ How to communicate the intent?
App
Task 2Task 1
Communication
➔ Propagate events from
bottom to top
➔ Use trigger method to
generate native event
➔ Use t-on- directive to catch
them
➔ Event payload is available
in the event.detail key
App
Task 2Task 1
7. Toggling tasks class Task extends Component {
toggleTask() {
this.trigger('toggle-task', {
id: this.props.task.id
});
}
}
// In App
<div class="task-list" t-on-toggle-
task="toggleTask">
class App extends Component {
toggleTask(ev) {
const task = this.tasks.find(t => t.id
=== ev.detail.id);
task.isCompleted = !task.isCompleted;
}
}
➔ Trigger event in Task
➔ Catch it in App
➔ Modify state in App
➔ Notice the event payload is actually
set in ev.detail
8. Deleting Tasks
<div class="task" ...>
...
<span class="delete" t-on-click="deleteTask"> </span>
</div>
class Task extends Component {
deleteTask() {
this.trigger('delete-task', {id: ...});
}
}
<div class="task-list"
t-on-toggle-task="toggleTask"
t-on-delete-task="deleteTask">
class App extends Component {
deleteTask(ev) {
const index = this.tasks.findIndex(t => t.id ===
ev.detail.id);
this.tasks.splice(index, 1);
}
}
➔ Add event handler in some
component
➔ Trigger event with proper payload
➔ Catch event in some parent
component
➔ Properly update state
Very common workflow:
9. Saving state to local
storage
class App extends Component {
constructor() {
super(...arguments);
const tasks = localStorage.getItem("todoapp");
if (tasks) {
for (let task of JSON.parse(tasks)) {
this.tasks.push(task);
this.nextId = Math.max(this.nextId, task.id + 1);
}
}
}
addTask(ev) {
...
localStorage.setItem("todoapp",
JSON.stringify(this.tasks));
}
toggleTask(ev) {
...
localStorage.setItem("todoapp",
JSON.stringify(this.tasks));
}
deleteTask(ev) {
...
localStorage.setItem("todoapp",
JSON.stringify(this.tasks));
}
}
➔ Need to load tasks in constructor
➔ And update localstorage whenever
an update is done
➔ Duplication is bad. We’ll solve that
later
What if we need
to test?
The App component uses localStorage.
Difficult to test.
Solution:
Dependency
Injection
10. Dependency Injection
class App extends Component {
constructor(localStorage) {
super();
this.localStorage = localStorage;
// replace all uses of localStorage by
this.localStorage
...
}
}
const app = new App(window.localStorage);
app.mount(document.body);
➔ Give localStorage instance in the
constructor
➔ Use it inside the App component
But, it only works with the root
component!
Owl solution: the env
App env
A
env
B
env
C
env
D
env
props props
props props
10. Dependency Injection
class App extends Component {
constructor() {
super();
const tasks =
this.env.localStorage.getItem("todoapp");
...
}
// replace all uses of this.localStorage
by this.env.localStorage
}
App.env.localStorage = window.localStorage;
const app = new App();
app.mount(document.body);
➔ Setup the App env before creating it
➔ It is now available in this.env for the
whole application
Issues:
● Some code duplication (with localstorage)
● App component does too much
● State management is all over the place
● Localstorage code is all over the place
11. Extracting concerns
We want components to be mostly
about UI (look and feel + event handling)
So, we want to extract:
➔ Task state management
➔ Persistence (local storage)
env
StoredTaskModel
TaskModel
App env
Task 1 env Task 2 env
11. Extracting concerns
class TaskModel extends owl.core.EventBus {
nextId = 1
tasks = [];
constructor(tasks) {
super()
for (let task of tasks) {
this.tasks.push(task);
this.nextId = Math.max(...);
}
}
addTask(title) {
const newTask = ...;
this.tasks.push(newTask);
this.trigger('update');
}
toggleTask(id) {
...
}
deleteTask(id) {
...
}
}
class StoredTaskModel extends TaskModel {
constructor(storage) {
const tasks = storage.getItem("todoapp");
super(tasks ? JSON.parse(tasks) : []);
this.on('update', this, () => {
storage.setItem("todoapp",
JSON.stringify(this.tasks))
});
}
}
11. Extracting concerns
class App extends Component {
constructor() {
super();
const model = new StoredTaskModel(
this.env.localStorage
);
model.on('update', this, this.render);
useSubEnv({model});
}
// access model with this.env.model (or
env.model in template)
}
class Task extends Component {
static template = TASK_TEMPLATE;
toggleTask() {
this.env.model.toggleTask(this.props.task.id);
}
deleteTask() {
this.env.model.deleteTask(this.props.task.id);
}
}
● Use composition (for StoredTaskmodel)
● Inject model in App
● Use a Store
● Make local storage key configurable
● Add filters
● Allow edition
github.com/ged-odoo/owl-todolist
Thank You

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

QWeb Report in odoo
QWeb Report in odooQWeb Report in odoo
QWeb Report in odoo
 
Cours 2 les composants
Cours 2 les composantsCours 2 les composants
Cours 2 les composants
 
How to develop automated tests
How to develop automated testsHow to develop automated tests
How to develop automated tests
 
Odoo Experience 2018 - The Odoo JS Framework
Odoo Experience 2018 - The Odoo JS FrameworkOdoo Experience 2018 - The Odoo JS Framework
Odoo Experience 2018 - The Odoo JS Framework
 
Angular js routing options
Angular js routing optionsAngular js routing options
Angular js routing options
 
New Framework - ORM
New Framework - ORMNew Framework - ORM
New Framework - ORM
 
Odoo Online platform: architecture and challenges
Odoo Online platform: architecture and challengesOdoo Online platform: architecture and challenges
Odoo Online platform: architecture and challenges
 
How to Define One2Many Field in Odoo 15
 How to Define One2Many Field in Odoo 15 How to Define One2Many Field in Odoo 15
How to Define One2Many Field in Odoo 15
 
How to Build Custom Module in Odoo 15
How to Build Custom Module in Odoo 15How to Build Custom Module in Odoo 15
How to Build Custom Module in Odoo 15
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux Introduction
 
Odoo.sh for Developers
Odoo.sh for DevelopersOdoo.sh for Developers
Odoo.sh for Developers
 
Odoo 3D Product View with Google Model-Viewer
Odoo 3D Product View with Google Model-ViewerOdoo 3D Product View with Google Model-Viewer
Odoo 3D Product View with Google Model-Viewer
 
Ngrx slides
Ngrx slidesNgrx slides
Ngrx slides
 
Deploying & Scaling your Odoo Server
Deploying & Scaling your Odoo ServerDeploying & Scaling your Odoo Server
Deploying & Scaling your Odoo Server
 
How to Choose the Proper Infra (Online, Odoo.sh, On premise)
How to Choose the Proper Infra (Online, Odoo.sh, On premise)How to Choose the Proper Infra (Online, Odoo.sh, On premise)
How to Choose the Proper Infra (Online, Odoo.sh, On premise)
 
Tutorial: Develop an App with the Odoo Framework
Tutorial: Develop an App with the Odoo FrameworkTutorial: Develop an App with the Odoo Framework
Tutorial: Develop an App with the Odoo Framework
 
View Inheritance in Odoo 16
View Inheritance in Odoo 16View Inheritance in Odoo 16
View Inheritance in Odoo 16
 
Odoo (Build module, Security, ORM)
Odoo (Build module, Security, ORM)Odoo (Build module, Security, ORM)
Odoo (Build module, Security, ORM)
 
Vuex
VuexVuex
Vuex
 
Introduction à React
Introduction à ReactIntroduction à React
Introduction à React
 

Ähnlich wie Owl: The New Odoo UI Framework

Javascript unit testing, yes we can e big
Javascript unit testing, yes we can   e bigJavascript unit testing, yes we can   e big
Javascript unit testing, yes we can e big
Andy Peterson
 
[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation
洪 鹏发
 

Ähnlich wie Owl: The New Odoo UI Framework (20)

Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applications
 
Lec9Handout.ppt
Lec9Handout.pptLec9Handout.ppt
Lec9Handout.ppt
 
Fundamental Concepts of React JS for Beginners.pdf
Fundamental Concepts of React JS for Beginners.pdfFundamental Concepts of React JS for Beginners.pdf
Fundamental Concepts of React JS for Beginners.pdf
 
Pluginkla2019 - React Presentation
Pluginkla2019 - React PresentationPluginkla2019 - React Presentation
Pluginkla2019 - React Presentation
 
Simple React Todo List
Simple React Todo ListSimple React Todo List
Simple React Todo List
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS Introduction
 
Enhance react app with patterns - part 1: higher order component
Enhance react app with patterns - part 1: higher order componentEnhance react app with patterns - part 1: higher order component
Enhance react app with patterns - part 1: higher order component
 
Intro react js
Intro react jsIntro react js
Intro react js
 
How to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescriptHow to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescript
 
Angular2 + rxjs
Angular2 + rxjsAngular2 + rxjs
Angular2 + rxjs
 
Javascript unit testing, yes we can e big
Javascript unit testing, yes we can   e bigJavascript unit testing, yes we can   e big
Javascript unit testing, yes we can e big
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 
React & The Art of Managing Complexity
React &  The Art of Managing ComplexityReact &  The Art of Managing Complexity
React & The Art of Managing Complexity
 
Lec7Handout.ppt
Lec7Handout.pptLec7Handout.ppt
Lec7Handout.ppt
 
Os Haase
Os HaaseOs Haase
Os Haase
 
Angular JS2 Training Session #2
Angular JS2 Training Session #2Angular JS2 Training Session #2
Angular JS2 Training Session #2
 
Introducing Struts 2
Introducing Struts 2Introducing Struts 2
Introducing Struts 2
 
React/Redux
React/ReduxReact/Redux
React/Redux
 
Fundamental concepts of react js
Fundamental concepts of react jsFundamental concepts of react js
Fundamental concepts of react js
 
[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation
 

Mehr von Odoo

Mehr von Odoo (20)

Timesheet Workshop: The Timesheet App People Love!
Timesheet Workshop: The Timesheet App People Love!Timesheet Workshop: The Timesheet App People Love!
Timesheet Workshop: The Timesheet App People Love!
 
Keynote - Vision & Strategy
Keynote - Vision & StrategyKeynote - Vision & Strategy
Keynote - Vision & Strategy
 
Opening Keynote - Unveilling Odoo 14
Opening Keynote - Unveilling Odoo 14Opening Keynote - Unveilling Odoo 14
Opening Keynote - Unveilling Odoo 14
 
Extending Odoo with a Comprehensive Budgeting and Forecasting Capability
Extending Odoo with a Comprehensive Budgeting and Forecasting CapabilityExtending Odoo with a Comprehensive Budgeting and Forecasting Capability
Extending Odoo with a Comprehensive Budgeting and Forecasting Capability
 
Managing Multi-channel Selling with Odoo
Managing Multi-channel Selling with OdooManaging Multi-channel Selling with Odoo
Managing Multi-channel Selling with Odoo
 
Product Configurator: Advanced Use Case
Product Configurator: Advanced Use CaseProduct Configurator: Advanced Use Case
Product Configurator: Advanced Use Case
 
Accounting Automation: How Much Money We Saved and How?
Accounting Automation: How Much Money We Saved and How?Accounting Automation: How Much Money We Saved and How?
Accounting Automation: How Much Money We Saved and How?
 
Rock Your Logistics with Advanced Operations
Rock Your Logistics with Advanced OperationsRock Your Logistics with Advanced Operations
Rock Your Logistics with Advanced Operations
 
Transition from a cost to a flow-centric organization
Transition from a cost to a flow-centric organizationTransition from a cost to a flow-centric organization
Transition from a cost to a flow-centric organization
 
Synchronization: The Supply Chain Response to Overcome the Crisis
Synchronization: The Supply Chain Response to Overcome the CrisisSynchronization: The Supply Chain Response to Overcome the Crisis
Synchronization: The Supply Chain Response to Overcome the Crisis
 
Running a University with Odoo
Running a University with OdooRunning a University with Odoo
Running a University with Odoo
 
Down Payments on Purchase Orders in Odoo
Down Payments on Purchase Orders in OdooDown Payments on Purchase Orders in Odoo
Down Payments on Purchase Orders in Odoo
 
Odoo Implementation in Phases - Success Story of a Retail Chain 3Sach food
Odoo Implementation in Phases - Success Story of a Retail Chain 3Sach foodOdoo Implementation in Phases - Success Story of a Retail Chain 3Sach food
Odoo Implementation in Phases - Success Story of a Retail Chain 3Sach food
 
Migration from Salesforce to Odoo
Migration from Salesforce to OdooMigration from Salesforce to Odoo
Migration from Salesforce to Odoo
 
Preventing User Mistakes by Using Machine Learning
Preventing User Mistakes by Using Machine LearningPreventing User Mistakes by Using Machine Learning
Preventing User Mistakes by Using Machine Learning
 
Becoming an Odoo Expert: How to Prepare for the Certification
Becoming an Odoo Expert: How to Prepare for the Certification Becoming an Odoo Expert: How to Prepare for the Certification
Becoming an Odoo Expert: How to Prepare for the Certification
 
Instant Printing of any Odoo Report or Shipping Label
Instant Printing of any Odoo Report or Shipping LabelInstant Printing of any Odoo Report or Shipping Label
Instant Printing of any Odoo Report or Shipping Label
 
How Odoo helped an Organization Grow 3 Fold
How Odoo helped an Organization Grow 3 FoldHow Odoo helped an Organization Grow 3 Fold
How Odoo helped an Organization Grow 3 Fold
 
From Shopify to Odoo
From Shopify to OdooFrom Shopify to Odoo
From Shopify to Odoo
 
Digital Transformation at Old MacDonald Farms: A Personal Story
Digital Transformation at Old MacDonald Farms: A Personal StoryDigital Transformation at Old MacDonald Farms: A Personal Story
Digital Transformation at Old MacDonald Farms: A Personal Story
 

Kürzlich hochgeladen

Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
dlhescort
 
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service NoidaCall Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
dlhescort
 
Call Girls From Pari Chowk Greater Noida ❤️8448577510 ⊹Best Escorts Service I...
Call Girls From Pari Chowk Greater Noida ❤️8448577510 ⊹Best Escorts Service I...Call Girls From Pari Chowk Greater Noida ❤️8448577510 ⊹Best Escorts Service I...
Call Girls From Pari Chowk Greater Noida ❤️8448577510 ⊹Best Escorts Service I...
lizamodels9
 
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
amitlee9823
 
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Anamikakaur10
 
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabiunwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
Abortion pills in Kuwait Cytotec pills in Kuwait
 
Insurers' journeys to build a mastery in the IoT usage
Insurers' journeys to build a mastery in the IoT usageInsurers' journeys to build a mastery in the IoT usage
Insurers' journeys to build a mastery in the IoT usage
Matteo Carbone
 

Kürzlich hochgeladen (20)

Falcon's Invoice Discounting: Your Path to Prosperity
Falcon's Invoice Discounting: Your Path to ProsperityFalcon's Invoice Discounting: Your Path to Prosperity
Falcon's Invoice Discounting: Your Path to Prosperity
 
Business Model Canvas (BMC)- A new venture concept
Business Model Canvas (BMC)-  A new venture conceptBusiness Model Canvas (BMC)-  A new venture concept
Business Model Canvas (BMC)- A new venture concept
 
Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
 
Eluru Call Girls Service ☎ ️93326-06886 ❤️‍🔥 Enjoy 24/7 Escort Service
Eluru Call Girls Service ☎ ️93326-06886 ❤️‍🔥 Enjoy 24/7 Escort ServiceEluru Call Girls Service ☎ ️93326-06886 ❤️‍🔥 Enjoy 24/7 Escort Service
Eluru Call Girls Service ☎ ️93326-06886 ❤️‍🔥 Enjoy 24/7 Escort Service
 
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service NoidaCall Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
 
Call Girls From Pari Chowk Greater Noida ❤️8448577510 ⊹Best Escorts Service I...
Call Girls From Pari Chowk Greater Noida ❤️8448577510 ⊹Best Escorts Service I...Call Girls From Pari Chowk Greater Noida ❤️8448577510 ⊹Best Escorts Service I...
Call Girls From Pari Chowk Greater Noida ❤️8448577510 ⊹Best Escorts Service I...
 
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
 
Call Girls In Panjim North Goa 9971646499 Genuine Service
Call Girls In Panjim North Goa 9971646499 Genuine ServiceCall Girls In Panjim North Goa 9971646499 Genuine Service
Call Girls In Panjim North Goa 9971646499 Genuine Service
 
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
 
Famous Olympic Siblings from the 21st Century
Famous Olympic Siblings from the 21st CenturyFamous Olympic Siblings from the 21st Century
Famous Olympic Siblings from the 21st Century
 
Value Proposition canvas- Customer needs and pains
Value Proposition canvas- Customer needs and painsValue Proposition canvas- Customer needs and pains
Value Proposition canvas- Customer needs and pains
 
Mondelez State of Snacking and Future Trends 2023
Mondelez State of Snacking and Future Trends 2023Mondelez State of Snacking and Future Trends 2023
Mondelez State of Snacking and Future Trends 2023
 
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabiunwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
 
Insurers' journeys to build a mastery in the IoT usage
Insurers' journeys to build a mastery in the IoT usageInsurers' journeys to build a mastery in the IoT usage
Insurers' journeys to build a mastery in the IoT usage
 
(Anamika) VIP Call Girls Napur Call Now 8617697112 Napur Escorts 24x7
(Anamika) VIP Call Girls Napur Call Now 8617697112 Napur Escorts 24x7(Anamika) VIP Call Girls Napur Call Now 8617697112 Napur Escorts 24x7
(Anamika) VIP Call Girls Napur Call Now 8617697112 Napur Escorts 24x7
 
Cracking the Cultural Competence Code.pptx
Cracking the Cultural Competence Code.pptxCracking the Cultural Competence Code.pptx
Cracking the Cultural Competence Code.pptx
 
Uneak White's Personal Brand Exploration Presentation
Uneak White's Personal Brand Exploration PresentationUneak White's Personal Brand Exploration Presentation
Uneak White's Personal Brand Exploration Presentation
 
👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...
👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...
👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...
 
How to Get Started in Social Media for Art League City
How to Get Started in Social Media for Art League CityHow to Get Started in Social Media for Art League City
How to Get Started in Social Media for Art League City
 
It will be International Nurses' Day on 12 May
It will be International Nurses' Day on 12 MayIt will be International Nurses' Day on 12 May
It will be International Nurses' Day on 12 May
 

Owl: The New Odoo UI Framework

  • 1.
  • 4. 1. Based on XML templates (QWeb) 2. JIT template compilation 3. Easy to integrate in Odoo assets pipeline
  • 5. 1. Based on XML templates (QWeb) 2. JIT template compilation 3. Easy to integrate in Odoo assets pipeline
  • 6. 1. Based on XML templates (QWeb) 2. JIT template compilation 3. Easy to integrate in Odoo assets pipeline
  • 7. Part 2 Owl design principles
  • 9. Modern UI toolset ● components ● hooks ● slots ● store ● ...
  • 11. Part 3 Let’s build a to-do list
  • 12.
  • 13. 1. Setting up the projecthooks, slots, store and more hooks, slots, store and more github.com/ged-odoo/owl-todolist
  • 14. 2. Adding the first component const { Component } = owl; const { xml } = owl.tags; const { whenReady } = owl.utils; // Owl Components class App extends Component { static template = xml`<div>todo app</div>`; } // Setup code function setup() { const app = new App(); app.mount(document.body); } whenReady(setup); ➔ Components are class, inherit from Component ➔ An Owl application is a (dynamic) tree of components, with a root ➔ It is mounted with the mount method ➔ The mount operation completes when all the sub component tree (if any) are ready ➔ Templates are inlined here
  • 15. 3. Displaying tasks ➔ Always useful to add demo data ➔ Template is standard QWeb ➔ qweb evaluation context = component instance ➔ Notice the t-key directive! const TASKS = [ { id: 1, title: "buy milk", isCompleted: true, }, { id: 2, title: "clean house", isCompleted: false, }, ]; class App extends Component { static template = xml` <div class="task-list"> <t t-foreach="tasks" t-as="task" t-key="task.id"> <div class="task"> <input type="checkbox" t-att-checked="task.isCompleted"/> <span><t t-esc="task.title"/></span> </div> </t> </div>`; tasks = TASKS; }
  • 16. 4. Style .task-list { width: 300px; margin: 50px auto; background: aliceblue; padding: 10px; } .task { font-size: 18px; color: #111111; } .task.done { opacity: 0.7; } <div class="task" t-att-class="task.isCompleted ? 'done' : ''"> ➔ class and t-att-class attributes can be combined app.css Template:
  • 17. 5. Extracting task as a subcomponent ➔ Most UI are divided into sub components ➔ Components are described by xml elements with a capital first letter ➔ Components attributes are given to actual sub component instance (props) const TASK_TEMPLATE = xml` <div class="task" t-att-class="props.task.isCompleted ? 'done':''"> <input type="checkbox" t-att-checked="props.task.isCompleted"/> <span><t t-esc="props.task.title"/></span> </div>`; class Task extends Component { static template = TASK_TEMPLATE; } const APP_TEMPLATE = xml` <div class="task-list"> <t t-foreach="tasks" t-as="task" t-key="task.id"> <Task task="task"/> </t> </div>`; class App extends Component { static template = APP_TEMPLATE; static components = { Task }; tasks = TASKS; }
  • 18. UI as a tree of components Root State A B C State State Props D EProps State Props
  • 19. State class App extends Component { tasks = TASKS; ... } ➔ Owned by a component ➔ May be reactive or not ➔ Only owner can update it ➔ Can give reference to other components (as props) <div class="task-list"> <t t-foreach="tasks" t-as="task" t-key="task.id"> <Task task="task"/> </t> </div> Props ➔ Can be accessed in this.props ➔ Owned by someone else ➔ Props cannot be updated by child component
  • 20. 6. Adding tasks <div class="todo-app"> <input placeholder="Enter a new task" t-on-keyup="addTask"/> <div class="task-list"> ... </div> </div> ➔ Can add event handler with t-on- directive ➔ Handler receive event as first argument ➔ Handler need to be a function in the rendering context (the component instance) addTask(ev) { // 13 is keycode for ENTER if (ev.keyCode === 13) { const title = ev.target.value.trim(); ev.target.value = ""; console.log('adding task', title); // todo } }
  • 21. 6. Adding tasks <input placeholder="Enter a new task" t-on-keyup="addTask" t-ref="add-input"/> ➔ Get reference with t-ref directive ➔ Can use mounted lifecycle method ➔ UseRef is our first hook const { useRef } = owl.hooks; class App extends Component { inputRef = useRef("add-input"); mounted() { this.inputRef.el.focus(); } ... }
  • 22. Components Lifecycle willPatch patched willUnmountconstructor willStart* mounted willUpdateProps*
  • 23. 6. Adding tasks class App extends Component { ... nextId = 1; tasks = []; ... addTask(ev) { // 13 is keycode for ENTER if (ev.keyCode === 13) { const title = ev.target.value.trim(); ev.target.value = ""; if (title) { const newTask = { id: this.nextId++, title: title, isCompleted: false, }; this.tasks.push(newTask); } } } } ➔ Generate some id number ➔ Add the task info to the task list But… It does not work!
  • 25. 6. Adding tasks // on top of the file const { useRef, useState } = owl.hooks; class App extends Component { tasks = useState([]); ... } ➔ Make the state reactive with useState hook ➔ It works with arrays and objects (even nested)
  • 26. 7. Toggling tasks <input type="checkbox" t-att- checked="props.task.isCompleted" t-on-click="toggleTask"/> class Task extends Component { static template = TASK_TEMPLATE; toggleTask() { // ??? } } ➔ Task component cannot change a task ➔ How to communicate the intent? App Task 2Task 1
  • 27. Communication ➔ Propagate events from bottom to top ➔ Use trigger method to generate native event ➔ Use t-on- directive to catch them ➔ Event payload is available in the event.detail key App Task 2Task 1
  • 28. 7. Toggling tasks class Task extends Component { toggleTask() { this.trigger('toggle-task', { id: this.props.task.id }); } } // In App <div class="task-list" t-on-toggle- task="toggleTask"> class App extends Component { toggleTask(ev) { const task = this.tasks.find(t => t.id === ev.detail.id); task.isCompleted = !task.isCompleted; } } ➔ Trigger event in Task ➔ Catch it in App ➔ Modify state in App ➔ Notice the event payload is actually set in ev.detail
  • 29. 8. Deleting Tasks <div class="task" ...> ... <span class="delete" t-on-click="deleteTask"> </span> </div> class Task extends Component { deleteTask() { this.trigger('delete-task', {id: ...}); } } <div class="task-list" t-on-toggle-task="toggleTask" t-on-delete-task="deleteTask"> class App extends Component { deleteTask(ev) { const index = this.tasks.findIndex(t => t.id === ev.detail.id); this.tasks.splice(index, 1); } } ➔ Add event handler in some component ➔ Trigger event with proper payload ➔ Catch event in some parent component ➔ Properly update state Very common workflow:
  • 30. 9. Saving state to local storage class App extends Component { constructor() { super(...arguments); const tasks = localStorage.getItem("todoapp"); if (tasks) { for (let task of JSON.parse(tasks)) { this.tasks.push(task); this.nextId = Math.max(this.nextId, task.id + 1); } } } addTask(ev) { ... localStorage.setItem("todoapp", JSON.stringify(this.tasks)); } toggleTask(ev) { ... localStorage.setItem("todoapp", JSON.stringify(this.tasks)); } deleteTask(ev) { ... localStorage.setItem("todoapp", JSON.stringify(this.tasks)); } } ➔ Need to load tasks in constructor ➔ And update localstorage whenever an update is done ➔ Duplication is bad. We’ll solve that later
  • 31. What if we need to test? The App component uses localStorage. Difficult to test.
  • 33. 10. Dependency Injection class App extends Component { constructor(localStorage) { super(); this.localStorage = localStorage; // replace all uses of localStorage by this.localStorage ... } } const app = new App(window.localStorage); app.mount(document.body); ➔ Give localStorage instance in the constructor ➔ Use it inside the App component But, it only works with the root component!
  • 34. Owl solution: the env App env A env B env C env D env props props props props
  • 35. 10. Dependency Injection class App extends Component { constructor() { super(); const tasks = this.env.localStorage.getItem("todoapp"); ... } // replace all uses of this.localStorage by this.env.localStorage } App.env.localStorage = window.localStorage; const app = new App(); app.mount(document.body); ➔ Setup the App env before creating it ➔ It is now available in this.env for the whole application
  • 36. Issues: ● Some code duplication (with localstorage) ● App component does too much ● State management is all over the place ● Localstorage code is all over the place
  • 37. 11. Extracting concerns We want components to be mostly about UI (look and feel + event handling) So, we want to extract: ➔ Task state management ➔ Persistence (local storage) env StoredTaskModel TaskModel App env Task 1 env Task 2 env
  • 38. 11. Extracting concerns class TaskModel extends owl.core.EventBus { nextId = 1 tasks = []; constructor(tasks) { super() for (let task of tasks) { this.tasks.push(task); this.nextId = Math.max(...); } } addTask(title) { const newTask = ...; this.tasks.push(newTask); this.trigger('update'); } toggleTask(id) { ... } deleteTask(id) { ... } } class StoredTaskModel extends TaskModel { constructor(storage) { const tasks = storage.getItem("todoapp"); super(tasks ? JSON.parse(tasks) : []); this.on('update', this, () => { storage.setItem("todoapp", JSON.stringify(this.tasks)) }); } }
  • 39. 11. Extracting concerns class App extends Component { constructor() { super(); const model = new StoredTaskModel( this.env.localStorage ); model.on('update', this, this.render); useSubEnv({model}); } // access model with this.env.model (or env.model in template) } class Task extends Component { static template = TASK_TEMPLATE; toggleTask() { this.env.model.toggleTask(this.props.task.id); } deleteTask() { this.env.model.deleteTask(this.props.task.id); } }
  • 40. ● Use composition (for StoredTaskmodel) ● Inject model in App ● Use a Store ● Make local storage key configurable ● Add filters ● Allow edition github.com/ged-odoo/owl-todolist

Hinweis der Redaktion

  1. Two years ago, I was working on the Odoo javascript codebase. I was sad, depressed, hopeless, lonely, cold. Why was it so frustrating to combine widgets together? To build an user interface. To add event listeners and properly clean them up? My life was dark and empty. No joy, nothing. But then, we imagined what the perfect developer experience should be. And so was born Owl, in an explosion of light… Ok, I am lying. But the point is that working with Odoo javascript has been a mixed experience in the past. Full of joy, but sometimes, frustrating. This is why we introduced last year a new javascript framework, named Owl, as a first step to solve our issues. For a little less than one year, we used Owl for all our new javascript code. For example, the new spreadsheet component in v14 is built entirely with owl. So far, it looks like the technology is really solid and is a huge improvement compared to what we had before. My name is Géry Debongnie, I am a lead developer at Odoo, working mostly on javascript projects, and today, for this technical talk, I will introduce the fundamentals of Owl.
  2. Like all modern applications, Odoo has a need for a good UI building block system, or framework. It is clear that the state of the art moved toward declarative programming, with good reasons. All modern frameworks are declarative at their core. But the Odoo widget system was designed a long time ago, and we feel the pain of maintaining a complex application. So, it is clear that odoo needs a better UI framework. And then, Odoo decided to make Owl. I think it is worth taking a few minutes explaining why. We are aware that creating a new framework from scratch seems like a terrible idea. Why not use React, or Vue? This is clearly very true in 99% of the time an existing framework fits your needs. But then it sometimes happens that we have different needs. Let me highlight 3 good reasons why we could not use one of these well-known, well maintained existing frameworks.
  3. blabla
  4. This is a really unusual requirement in most web applications, but it is very important for Odoo.
  5. This is more a self-imposed constraint, because we could actually change the way we manage assets. It is however not trivial, since Odoo is modular, and a lot of work is required to make it work in a natural/efficient way
  6. Owl is a powerful tool. It solves all our main needs. But as with all tools, it is designed to solve some kind of problems, and may not be appropriate for other situations. So, let us discuss what Owl is designed for, and what it is not...
  7. Owl is not designed to solve all your architectural issues. It is not angular. Owl is designed to be kind of low level abstraction. It wants to stay out of your way. You can design an application the way you like, Owl will just give you some building blocks, and go along with your design. It is not intended to solve all problems.
  8. Finally, Owl provides powerful abstractions, such as declarative UI, hooks, slots, store and more. It takes the best ideas from all other frameworks and blend them together in a coherent experience. I can tell you that learning and using Owl was quite easy for all our developers which had some React or Vue experience.
  9. very proud of this… really powerful, implemented with a concept coming from react: the fiber. probably the most technically difficult part of owl. and the best part of it is that it is mostly transparent for developers. If some component chose to implement one of the asynchronous lifecycle method, then all its parents will properly coordinate with it. No code change is required. The asynchronous behaviour will propagate automatically to all parent components.
  10. Now, enough theory. Let us do something with our hands… It’s time to actually use Owl out there in the real world! We will build a real application to discuss some interesting owl concepts and ideas
  11. we are going to make a simple todo list… This component will manage of list of tasks, and allow the user to add/toggle and delete tasks. this is just going to be an excuse to introduce various ideas and concepts defined by Owl to build an interface. The code will be a little bit over engineered, but this is for the greater good
  12. not very interesting nor owl specific. The kind of setup you will use in practice depends on your specific needs. For this talk, I will simply use a single html/js/css file structure. The repo here contains all major steps for this talk as different commit, in case you are interested in playing with the code
  13. Templates are inlined in this talk for
  14. improve template style (t-key on same line, 2 space indent, …)
  15. Templates are inlined in this talk for
  16. Templates are inlined in this talk for
  17. Templates are inlined in this talk for
  18. Templates are inlined in this talk for
  19. add legend => async add other slides? mounted => willUnmount, patched => willUpdateProps => willpatch => patched
  20. Templates are inlined in this talk for
  21. Templates are inlined in this talk for
  22. Templates are inlined in this talk for
  23. Templates are inlined in this talk for
  24. Templates are inlined in this talk for
  25. Templates are inlined in this talk for
  26. let’s give the local storage to the App component
  27. Templates are inlined in this talk for
  28. Templates are inlined in this talk for
  29. Not everything in an owl application need to be a componenet.
  30. This StoredTaskModel uses inheritance. Maybe we should use composition instead. or mixins or whatever you prefer!
  31. File is currently 130 lines (so, JS + templates) As you can see, there are a lot of improvements that we can still do. Such is life, always imperfect. In this talk, we explored a lot of interesting ideas that you can use while working with Owl. I hope that this talk was useful to you and that you now feel empowered to make great things with the Owl framework.
  32. Thank you for your attention! Oh, if you are interested in the challenges of working with owl inside odoo, there is a talk on that topic coming up right now. Thank you again!