Skip to content

Commit 24f639f

Browse files
committed
[IMP] awesome_owl: Chapter 1: Owl components
1 parent ad217c7 commit 24f639f

File tree

11 files changed

+242
-3
lines changed

11 files changed

+242
-3
lines changed

awesome_owl/static/src/card/card.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/** @odoo-module **/
2+
3+
import { Component, useState } from "@odoo/owl";
4+
5+
export class Card extends Component {
6+
static template = "awesome_owl.card";
7+
8+
static props = {
9+
title: { type: String },
10+
slots: { type: Object },
11+
// content: { type: String }, removed following 13. Generic Card with slots
12+
}
13+
14+
setup() {
15+
this.opened = useState({ value: true });
16+
}
17+
18+
toggleOpened() {
19+
this.opened.value = !this.opened.value;
20+
}
21+
}

awesome_owl/static/src/card/card.xml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<templates xml:space="preserve">
3+
4+
<t t-name="awesome_owl.card">
5+
<div class="card d-inline-block m-2" style="width: 18rem;">
6+
<div class="card-body">
7+
<h5 class="card-title">
8+
<p><t t-esc="props.title" /></p>
9+
<button t-on-click="toggleOpened">Toggle</button>
10+
</h5>
11+
<p class="card-text" t-if="opened.value">
12+
<!-- <t t-out="props.content" removed following 13. Generic Card with slots/> -->
13+
<t t-slot="default" />
14+
</p>
15+
</div>
16+
</div>
17+
</t>
18+
19+
</templates>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/** @odoo-module **/
2+
3+
import { Component, useState } from "@odoo/owl";
4+
5+
export class Counter extends Component {
6+
static template = "awesome_owl.counter";
7+
8+
static props = {
9+
onChange: { type: Function, optional: true },
10+
}
11+
12+
setup() {
13+
this.state = useState({ value: 0 });
14+
}
15+
16+
increment() {
17+
this.state.value++;
18+
19+
if (this.props.onChange) {
20+
this.props.onChange();
21+
}
22+
}
23+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<templates xml:space="preserve">
3+
4+
<t t-name="awesome_owl.counter">
5+
<div class="card d-inline-block m-2" style="width: 18rem;">
6+
<div class="card-body">
7+
<p>Counter: <t t-esc="state.value" /></p>
8+
<button class="btn btn-primary" t-on-click="increment">Increment</button>
9+
</div>
10+
</div>
11+
</t>
12+
13+
</templates>

awesome_owl/static/src/playground.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
11
/** @odoo-module **/
22

3-
import { Component } from "@odoo/owl";
3+
import { Component, markup, useState } from "@odoo/owl";
4+
import { Card } from "./card/card";
5+
import { Counter } from "./counter/counter";
6+
import { TodoList } from "./todolist/todolist";
47

58
export class Playground extends Component {
9+
static components = { Counter, Card, TodoList };
10+
611
static template = "awesome_owl.playground";
12+
13+
static props = {};
14+
15+
html1 = "<div style=\"background-color: red\">some content</div>";
16+
html2 = markup("<div style=\"background-color: red\">some content</div>");
17+
18+
setup() {
19+
this.sum = useState({ value: 0 });
20+
}
21+
22+
incrementSum() {
23+
this.sum.value++;
24+
}
725
}

awesome_owl/static/src/playground.xml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1-
<?xml version="1.0" encoding="UTF-8" ?>
1+
<?xml version="1.0" encoding="UTF-8"?>
22
<templates xml:space="preserve">
33

44
<t t-name="awesome_owl.playground">
55
<div class="p-3">
6-
hello world
6+
hello world, The sum is <t t-esc="sum.value" />
7+
</div>
8+
<div>
9+
<Counter onChange.bind="incrementSum" />
10+
<Counter onChange.bind="incrementSum" />
11+
</div>
12+
<div>
13+
<Card title="'my title'">some content</Card>
14+
<Card title="'my title'"><t t-out="this.html1" /></Card>
15+
<Card title="'my title'"><t t-out="this.html2" /></Card>
16+
<!-- <Card title="'my title'" content="0" /> Invalid props for component 'Card': 'content' is not a string -->
17+
<Card title="'my title'"><Counter /></Card>
18+
</div>
19+
<div>
20+
<TodoList />
721
</div>
822
</t>
923

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/** @odoo-module **/
2+
3+
import { Component } from "@odoo/owl";
4+
5+
export class TodoItem extends Component {
6+
static template = "awesome_owl.todoitem";
7+
8+
static props = {
9+
todo: {
10+
type: Object,
11+
shape: {
12+
id: Number,
13+
description: String,
14+
isCompleted: Boolean,
15+
},
16+
},
17+
removeTodo: { type: Function },
18+
}
19+
20+
toggleState(ev) {
21+
if (!ev.target) return;
22+
23+
this.props.todo.isCompleted = ev.target.checked;
24+
}
25+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<templates xml:space="preserve">
3+
4+
<t t-name="awesome_owl.todoitem">
5+
<input
6+
type="checkbox"
7+
t-att-checked="props.todo.isCompleted"
8+
t-on-change="toggleState"
9+
style="display: inline-block; margin-right: 5px;" />
10+
<div
11+
t-att-class="{
12+
'text-decoration-line-through' : props.todo.isCompleted,
13+
'text-muted': props.todo.isCompleted,
14+
}"
15+
style="display: inline-block;" >
16+
<t t-esc="props.todo.id" />. <t t-esc="props.todo.description" />
17+
</div>
18+
<span
19+
class="fa fa-remove"
20+
t-on-click="this.props.removeTodo"
21+
style="display: inline-block; margin-left: 5px; color: red;" />
22+
</t>
23+
24+
</templates>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/** @odoo-module **/
2+
3+
import { Component, useRef, useState } from "@odoo/owl";
4+
import { useAutofocus } from "../utils";
5+
import { TodoItem } from "./todoitem";
6+
7+
export class TodoList extends Component {
8+
static components = { TodoItem };
9+
10+
static template = "awesome_owl.todolist";
11+
12+
static props = {};
13+
14+
setup() {
15+
this.id = 1; // could be calculated every iteration but would get very slow with a lot of todos
16+
this.todos = useState([
17+
// removed following 9. Adding a todo
18+
// { id: 2, description: "write tutorial", isCompleted: true },
19+
// { id: 3, description: "buy milk", isCompleted: false },
20+
]);
21+
this.inputRef = useRef("add_task");
22+
useAutofocus("add_task");
23+
}
24+
25+
addTodo(ev) {
26+
if (ev.keyCode != 13) return;
27+
28+
if (!this.inputRef.el) return;
29+
30+
const desc = this.inputRef.el.value;
31+
32+
if (desc === "") return;
33+
34+
this.todos.push({
35+
id: this.id,
36+
description: desc,
37+
isCompleted: false,
38+
});
39+
40+
this.inputRef.el.value = "";
41+
this.id++;
42+
}
43+
44+
removeTodo(ev) {
45+
// is there not a better way ??? this doesn't feel good
46+
const elemId = parseInt(ev.target.parentNode.childNodes[1].childNodes[0].textContent);
47+
48+
if (elemId < 0 || elemId >= this.id) return;
49+
50+
const index = this.todos.findIndex((elem) => elem.id === elemId);
51+
if (index >= 0) {
52+
// remove the element at index from list
53+
this.todos.splice(index, 1);
54+
}
55+
}
56+
}
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+
4+
<t t-name="awesome_owl.todolist">
5+
<div class="card d-inline-block m-2" style="width: 18rem;">
6+
<div class="card-body">
7+
<input type="text" class="" placeholder="Enter a new task" t-on-keyup="addTodo" t-ref="add_task"/>
8+
<div t-foreach="todos" t-as="todo" t-key="todo_index" style="margin: 2px;">
9+
<TodoItem todo="todo" removeTodo.bind="removeTodo" />
10+
</div>
11+
</div>
12+
</div>
13+
</t>
14+
15+
</templates>

0 commit comments

Comments
 (0)