Skip to content

Commit 3f88705

Browse files
committed
[ADD] awesome_owl: complete custom OWL component module
Implemented awesome_owl to render dynamic frontend components within the Odoo environment.The module includes an OWL component, JS logic, and integration with QWeb templates. It demonstrates how to use client-side rendering with OWL in a modular and reusable way and serves as a foundational example for building interactive UI features using OWL in Odoo.
1 parent 8770246 commit 3f88705

File tree

12 files changed

+150
-59
lines changed

12 files changed

+150
-59
lines changed

awesome_owl/static/src/card/card.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
/** @odoo-module **/
22

3-
import { Component} from "@odoo/owl";
3+
import { Component, useState } from "@odoo/owl"
44

55
export class Card extends Component {
6-
static template = "awesome_owl.Card";
6+
static template = "awesome_owl.Card"
77
static props = {
8-
title : {type: String},
9-
content : String,
8+
title: String,
9+
slots: {
10+
type: Object,
11+
shape: { default: true },
12+
},
13+
};
14+
setup() {
15+
this.state = useState({ isToggled: true });
1016
}
11-
}
17+
toggle() {
18+
this.state.isToggled = !this.state.isToggled;
19+
}
20+
}

awesome_owl/static/src/card/card.xml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@
33
<t t-name="awesome_owl.Card">
44
<div class="card d-inline-block m-2" style="width: 18rem;">
55
<div class="card-body">
6-
<h5 class="card-title"><t t-out="props.title"/></h5>
7-
<p class="card-text"><t t-out="props.content"/></p>
6+
<h5 class="card-title">
7+
<t t-out="props.title" />
8+
<!-- <t t-out="props.content" /> -->
9+
<button class="btn" t-on-click="toggle">Toggle Button</button>
10+
</h5>
11+
<p class="card-text" t-if="state.isToggled">
12+
<t t-slot="default" />
13+
</p>
814
</div>
915
</div>
1016
</t>
11-
</templates>
17+
</templates>

awesome_owl/static/src/counter/counter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ export class Counter extends Component {
1818
this.props.onChange(this.state.value);
1919
}
2020
}
21-
}
21+
}

awesome_owl/static/src/counter/counter.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
<button class="btn btn-primary" t-on-click="increment" style="background-color: blue; color: white;">Increment</button>
77
</div>
88
</t>
9-
</templates>
9+
</templates>

awesome_owl/static/src/playground.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/** @odoo-module **/
22

3-
import { Component, useState } from "@odoo/owl";
3+
import { Component, markup, useState } from "@odoo/owl";
44
import { Counter } from "./counter/counter";
55
import { Card } from "./card/card";
6-
import { TodoList} from "./todolist/todo_list"
6+
import { TodoList} from "./todolist/todolist"
77

88
export class Playground extends Component {
99
static template = "awesome_owl.playground";
@@ -15,4 +15,6 @@ export class Playground extends Component {
1515
incrementSum(value){
1616
this.state.sum += 1;
1717
}
18+
content1 = "<div class='text-primary'>some content</div>"
19+
content2 = markup("<div class='text-primary'>some content</div>")
1820
}

awesome_owl/static/src/playground.xml

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
1-
<?xml version="1.0" encoding="UTF-8" ?>
1+
<?xml version="1.0" encoding="UTF-8"?>
22
<templates xml:space="preserve">
3-
43
<t t-name="awesome_owl.playground">
5-
<div>
6-
<span>hello</span>
7-
<br/><br/>
4+
<div class="p-3">
5+
<span>hello world</span>
6+
<Counter onChange.bind="incrementSum" />
87
<Counter onChange.bind="incrementSum" />
9-
<Counter onChange.bind="incrementSum"/>
108
</div>
119
<div>
12-
<p>the sum is : <t t-esc="state.sum"/></p>
13-
</div><br/><br/>
14-
<Card title="'1st card'" content="'first content'"/>
15-
<Card title="'2st card'" content="'this is real content'"/>
16-
<Card title="'3st card'" content="'last content'"/>
17-
18-
<TodoList/>
10+
<p>The Sum is: <t t-esc="state.sum" /></p>
11+
</div>
12+
<div class="p-5">
13+
<Card title="'card 1'">
14+
<p>This is the content of Card 1.</p>
15+
</Card>
16+
<Card title="'Card 2'">
17+
<Counter onChange.bind="incrementSum" />
18+
</Card>
19+
</div>
20+
<div class="d-inline-flex border m-5 p-5">
21+
<TodoList />
22+
</div>
1923
</t>
20-
2124
</templates>

awesome_owl/static/src/todolist/todo_list.js

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
/** @odoo-module **/
22

3-
import { Component, xml } from "@odoo/owl";
3+
import { Component } from "@odoo/owl";
44

55
export class TodoItem extends Component {
6-
static template = xml/* xml */`
7-
<div>
8-
<t t-esc="props.todo.id"/> .
9-
<t t-esc="props.todo.description" />
10-
</div>
11-
`;
12-
6+
static template = "awesome_owl.TodoItem";
137
static props = {
148
todo: {
159
type: Object,
@@ -20,5 +14,7 @@ export class TodoItem extends Component {
2014
},
2115
optional: false,
2216
},
17+
toggleState: Function,
18+
todoDelete: Function,
2319
};
24-
}
20+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<templates xml:space="preserve">
3+
<t t-name="awesome_owl.TodoItem">
4+
<div t-attf-class="mb-2 p-2 border rounded {{ props.todo.isCompleted ? 'text-muted text-decoration-line-through' : '' }}">
5+
<input type="checkbox"
6+
t-att-checked="props.todo.isCompleted"
7+
t-on-change="() => props.toggleState(props.todo.id)" />
8+
<t t-esc="props.todo.id" /> .
9+
<t t-esc="props.todo.description" />
10+
<span class="fa fa-remove text-danger ms-2"
11+
style="cursor: pointer"
12+
t-on-click="() => props.todoDelete(props.todo.id)"/>
13+
</div>
14+
</t>
15+
</templates>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/** @odoo-module **/
2+
3+
import { Component, useState } from "@odoo/owl";
4+
import { TodoItem } from "./todoitem";
5+
import { useAutofocus } from "../utils/utils";
6+
7+
export class TodoList extends Component {
8+
static template = "awesome_owl.TodoList";
9+
static components = { TodoItem };
10+
11+
setup() {
12+
this.state = useState({
13+
text: "",
14+
todos: [],
15+
nextId: 1,
16+
});
17+
this.inputRef = useAutofocus("input");
18+
this.toggleState = this.toggleState.bind(this);
19+
this.todoDelete = this.todoDelete.bind(this);
20+
}
21+
22+
addTodo(ev) {
23+
if (ev.key === "Enter") {
24+
const description = this.state.text.trim();
25+
if (!description) return;
26+
27+
this.state.todos.push({
28+
id: this.state.nextId++,
29+
description: description,
30+
isCompleted: false,
31+
});
32+
this.state.text = "";
33+
}
34+
}
35+
36+
toggleState(todoId) {
37+
const todo = this.state.todos.find((t) => t.id === todoId);
38+
if (todo) {
39+
todo.isCompleted = !todo.isCompleted;
40+
}
41+
}
42+
todoDelete(todoId) {
43+
const index = this.state.todos.findIndex((t) => t.id === todoId);
44+
if (index >= 0) {
45+
this.state.todos.splice(index, 1);
46+
for (let i = index; i < this.state.todos.length; i++) {
47+
this.state.todos[i].id = i + 1;
48+
}
49+
}
50+
this.state.nextId = this.state.todos.length + 1;
51+
}
52+
}

0 commit comments

Comments
 (0)