From c85402826aa9f9bb14193ef1c7ac1ff8f7808783 Mon Sep 17 00:00:00 2001 From: vikri-odoo Date: Wed, 24 Dec 2025 16:45:44 +0100 Subject: [PATCH 1/3] [ADD] new components added for js tutorials 1.Counter component added 2.Card component added 3.Todo basic components added --- awesome_owl/static/src/card/card.js | 14 +++++++++++ awesome_owl/static/src/card/card.xml | 17 ++++++++++++++ awesome_owl/static/src/counter/counter.js | 23 +++++++++++++++++++ awesome_owl/static/src/counter/counter.xml | 9 ++++++++ awesome_owl/static/src/playground.js | 15 +++++++++++- awesome_owl/static/src/playground.xml | 10 +++++--- awesome_owl/static/src/todo/item/todo_item.js | 19 +++++++++++++++ .../static/src/todo/item/todo_item.xml | 11 +++++++++ awesome_owl/static/src/todo/list/todo_list.js | 22 ++++++++++++++++++ .../static/src/todo/list/todo_list.xml | 11 +++++++++ 10 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 awesome_owl/static/src/card/card.js create mode 100644 awesome_owl/static/src/card/card.xml create mode 100644 awesome_owl/static/src/counter/counter.js create mode 100644 awesome_owl/static/src/counter/counter.xml create mode 100644 awesome_owl/static/src/todo/item/todo_item.js create mode 100644 awesome_owl/static/src/todo/item/todo_item.xml create mode 100644 awesome_owl/static/src/todo/list/todo_list.js create mode 100644 awesome_owl/static/src/todo/list/todo_list.xml diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js new file mode 100644 index 00000000000..0a356c3b46c --- /dev/null +++ b/awesome_owl/static/src/card/card.js @@ -0,0 +1,14 @@ +import { Component } from "@odoo/owl"; + +export class Card extends Component { + static template = "awesome_owl.card"; + + static props = { + title: { + type: String, + }, + content: { + type: String, + } + } +} diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml new file mode 100644 index 00000000000..4eb2359d045 --- /dev/null +++ b/awesome_owl/static/src/card/card.xml @@ -0,0 +1,17 @@ + + + + +
+
+
+ +
+

+ +

+
+
+
+ +
diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js new file mode 100644 index 00000000000..3d0c528e96c --- /dev/null +++ b/awesome_owl/static/src/counter/counter.js @@ -0,0 +1,23 @@ +import { Component, useState } from "@odoo/owl"; + +export class Counter extends Component { + static template = "awesome_owl.counter"; + + static props = { + onChange: { + type: Function, + optional: true + } + } + + setup() { + this.state = useState({ value: 0}); + } + + increment() { + this.state.value++; + if(this.props.onChange) { + this.props.onChange(); + } + } +} diff --git a/awesome_owl/static/src/counter/counter.xml b/awesome_owl/static/src/counter/counter.xml new file mode 100644 index 00000000000..5e0ec2135c0 --- /dev/null +++ b/awesome_owl/static/src/counter/counter.xml @@ -0,0 +1,9 @@ + + + + +

Counter:

+ +
+ +
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 4ac769b0aa5..0a7ea38f78f 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,5 +1,18 @@ -import { Component } from "@odoo/owl"; +import { Component, useState } from "@odoo/owl"; +import { Counter } from "./counter/counter"; +import { Card } from "./card/card"; +import {TodoList} from "./todo/list/todo_list"; export class Playground extends Component { static template = "awesome_owl.playground"; + + static components = { Counter, Card, TodoList }; + + setup() { + this.state = useState({value: 0}); + } + + incrementSum() { + this.state.value++; + } } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 4fb905d59f9..d371115e428 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -2,9 +2,13 @@ -
- hello world -
+

My Counter

+ + + + +

Sum:

+
diff --git a/awesome_owl/static/src/todo/item/todo_item.js b/awesome_owl/static/src/todo/item/todo_item.js new file mode 100644 index 00000000000..8ef0284175b --- /dev/null +++ b/awesome_owl/static/src/todo/item/todo_item.js @@ -0,0 +1,19 @@ +import { Component } from "@odoo/owl"; +import {Card} from "../../card/card"; + +export class TodoItem extends Component { + static template = "awesome_owl.todo_item"; + + static Components = [ Card ] + + static props = { + todo: { + type: Object, + shape: { + id: Number, + description: String, + isCompleted: Boolean, + } + } + } +} diff --git a/awesome_owl/static/src/todo/item/todo_item.xml b/awesome_owl/static/src/todo/item/todo_item.xml new file mode 100644 index 00000000000..7cbc7cea19c --- /dev/null +++ b/awesome_owl/static/src/todo/item/todo_item.xml @@ -0,0 +1,11 @@ + + + + +
+ + +
+
+ +
diff --git a/awesome_owl/static/src/todo/list/todo_list.js b/awesome_owl/static/src/todo/list/todo_list.js new file mode 100644 index 00000000000..1355fc2a8e8 --- /dev/null +++ b/awesome_owl/static/src/todo/list/todo_list.js @@ -0,0 +1,22 @@ +import {Component, useState} from "@odoo/owl"; +import {TodoItem} from "../item/todo_item"; + +export class TodoList extends Component { + static template = "awesome_owl.todo_list"; + + static components = {TodoItem}; + + static props = { + items: { + type: Array, + optional: true, + } + } + + setup() { + this.props.items = useState([ + { id: 1, description: "buy Beer", isCompleted: true }, + { id: 2, description: "buy Chicken", isCompleted: false }, + ]) + } +} diff --git a/awesome_owl/static/src/todo/list/todo_list.xml b/awesome_owl/static/src/todo/list/todo_list.xml new file mode 100644 index 00000000000..ec7822f0a99 --- /dev/null +++ b/awesome_owl/static/src/todo/list/todo_list.xml @@ -0,0 +1,11 @@ + + + + + + +
+
+
+ +
From 6cc6cfd4a880bbca034c2e80fa5a66683f1a0818 Mon Sep 17 00:00:00 2001 From: vikri-odoo Date: Fri, 26 Dec 2025 11:31:29 +0100 Subject: [PATCH 2/3] [ADD] complete the chapter 1 tutorial 1.Small Todo App components added 2.use of slots to pass the dynamic contents to the components --- awesome_owl/static/src/card/card.js | 17 +++++-- awesome_owl/static/src/card/card.xml | 17 +++---- awesome_owl/static/src/counter/counter.js | 6 +-- awesome_owl/static/src/main.js | 9 ++-- awesome_owl/static/src/playground.js | 8 ++-- awesome_owl/static/src/playground.xml | 13 +++-- awesome_owl/static/src/todo/item/todo_item.js | 18 ++++++- .../static/src/todo/item/todo_item.xml | 5 +- awesome_owl/static/src/todo/list/todo_list.js | 48 +++++++++++++++++-- .../static/src/todo/list/todo_list.xml | 12 +++-- awesome_owl/static/src/utils/utils.js | 3 ++ 11 files changed, 116 insertions(+), 40 deletions(-) create mode 100644 awesome_owl/static/src/utils/utils.js diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index 0a356c3b46c..97954973c5d 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -1,4 +1,4 @@ -import { Component } from "@odoo/owl"; +import {Component, useState} from "@odoo/owl"; export class Card extends Component { static template = "awesome_owl.card"; @@ -7,8 +7,19 @@ export class Card extends Component { title: { type: String, }, - content: { - type: String, + slots: { + type: Object, + shape:{ + default: Object, + } } } + + setup() { + this.state = useState({visible: true}); + } + + showContent() { + this.state.visible = !this.state.visible; + } } diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index 4eb2359d045..765b1bb3cad 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -3,15 +3,16 @@
-
-
- -
-

- -

+
+
+ + +
+

+ +

+
-
diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js index 3d0c528e96c..4a017a1cb68 100644 --- a/awesome_owl/static/src/counter/counter.js +++ b/awesome_owl/static/src/counter/counter.js @@ -1,4 +1,4 @@ -import { Component, useState } from "@odoo/owl"; +import {Component, useState} from "@odoo/owl"; export class Counter extends Component { static template = "awesome_owl.counter"; @@ -11,12 +11,12 @@ export class Counter extends Component { } setup() { - this.state = useState({ value: 0}); + this.state = useState({value: 0}); } increment() { this.state.value++; - if(this.props.onChange) { + if (this.props.onChange) { this.props.onChange(); } } diff --git a/awesome_owl/static/src/main.js b/awesome_owl/static/src/main.js index 1aaea902b55..d822c898ee1 100644 --- a/awesome_owl/static/src/main.js +++ b/awesome_owl/static/src/main.js @@ -1,12 +1,11 @@ -import { whenReady } from "@odoo/owl"; -import { mountComponent } from "@web/env"; -import { Playground } from "./playground"; +import {whenReady} from "@odoo/owl"; +import {mountComponent} from "@web/env"; +import {Playground} from "./playground"; const config = { dev: true, - name: "Owl Tutorial" + name: "Owl Tutorial" }; // Mount the Playground component when the document.body is ready whenReady(() => mountComponent(Playground, document.body, config)); - diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 0a7ea38f78f..a919d50ac38 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,12 +1,12 @@ -import { Component, useState } from "@odoo/owl"; -import { Counter } from "./counter/counter"; -import { Card } from "./card/card"; +import {Component, useState} from "@odoo/owl"; +import {Counter} from "./counter/counter"; +import {Card} from "./card/card"; import {TodoList} from "./todo/list/todo_list"; export class Playground extends Component { static template = "awesome_owl.playground"; - static components = { Counter, Card, TodoList }; + static components = {Counter, Card, TodoList}; setup() { this.state = useState({value: 0}); diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index d371115e428..441eb9b0392 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -3,12 +3,15 @@

My Counter

- - - - + + + + + + +

Sum:

- +
diff --git a/awesome_owl/static/src/todo/item/todo_item.js b/awesome_owl/static/src/todo/item/todo_item.js index 8ef0284175b..c8a34cc8cc1 100644 --- a/awesome_owl/static/src/todo/item/todo_item.js +++ b/awesome_owl/static/src/todo/item/todo_item.js @@ -1,10 +1,10 @@ -import { Component } from "@odoo/owl"; +import {Component} from "@odoo/owl"; import {Card} from "../../card/card"; export class TodoItem extends Component { static template = "awesome_owl.todo_item"; - static Components = [ Card ] + static Components = [Card] static props = { todo: { @@ -14,6 +14,20 @@ export class TodoItem extends Component { description: String, isCompleted: Boolean, } + }, + toggleState: { + type: Function + }, + removeTodo: { + type: Function } } + + changeCheckbox(ev) { + this.props.toggleState(this.props.todo.id, ev.target.checked); + } + + removeTodo() { + this.props.removeTodo(this.props.todo.id) + } } diff --git a/awesome_owl/static/src/todo/item/todo_item.xml b/awesome_owl/static/src/todo/item/todo_item.xml index 7cbc7cea19c..c8a347482eb 100644 --- a/awesome_owl/static/src/todo/item/todo_item.xml +++ b/awesome_owl/static/src/todo/item/todo_item.xml @@ -2,9 +2,12 @@ -
+
+ +
diff --git a/awesome_owl/static/src/todo/list/todo_list.js b/awesome_owl/static/src/todo/list/todo_list.js index 1355fc2a8e8..e601818aae6 100644 --- a/awesome_owl/static/src/todo/list/todo_list.js +++ b/awesome_owl/static/src/todo/list/todo_list.js @@ -1,5 +1,6 @@ -import {Component, useState} from "@odoo/owl"; +import {Component, useState, useRef, onMounted} from "@odoo/owl"; import {TodoItem} from "../item/todo_item"; +import {useAutoFocus} from "../../utils/utils"; export class TodoList extends Component { static template = "awesome_owl.todo_list"; @@ -14,9 +15,46 @@ export class TodoList extends Component { } setup() { - this.props.items = useState([ - { id: 1, description: "buy Beer", isCompleted: true }, - { id: 2, description: "buy Chicken", isCompleted: false }, - ]) + this.props.items = useState([]) + this.descriptionRef = useRef('descriptionInput'); + this.nextId = 1; + onMounted(() => { + useAutoFocus(this.descriptionRef.el) + }); + } + + #checkDescription() { + return this.descriptionRef?.el?.value?.trim(); + } + + addTodoItem() { + if (this.#checkDescription()) { + this.props.items.push({ + id: this.nextId++, + description: this.descriptionRef.el.value, + isCompleted: false + }) + this.descriptionRef.el.value = ''; + } + } + + checkAndAddTask(ev) { + if (ev.keyCode === 13 && this.#checkDescription()) { + this.addTodoItem(); + } + } + + toggleTodoState = (id, isChecked) => { + const element = this.props.items.find(item => item.id === id); + if (element) { + element.isCompleted = isChecked; + } + } + + removeTodoItem = (id) => { + const index = this.props.items.findIndex(item => item.id === id); + if(index >= 0) { + this.props.items.splice(index, 1); + } } } diff --git a/awesome_owl/static/src/todo/list/todo_list.xml b/awesome_owl/static/src/todo/list/todo_list.xml index ec7822f0a99..17cc4897782 100644 --- a/awesome_owl/static/src/todo/list/todo_list.xml +++ b/awesome_owl/static/src/todo/list/todo_list.xml @@ -2,10 +2,14 @@ - - -
-
+
+ + + + +
+
+
diff --git a/awesome_owl/static/src/utils/utils.js b/awesome_owl/static/src/utils/utils.js new file mode 100644 index 00000000000..28d041cc7aa --- /dev/null +++ b/awesome_owl/static/src/utils/utils.js @@ -0,0 +1,3 @@ +export const useAutoFocus = (el) => { + el?.focus(); +} \ No newline at end of file From d62bbe3b4e7d817e94c94d54f0e536ad41c7bd41 Mon Sep 17 00:00:00 2001 From: vikri-odoo Date: Fri, 26 Dec 2025 11:33:17 +0100 Subject: [PATCH 3/3] [LINT] extra line at the end of utils.js --- awesome_owl/static/src/utils/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awesome_owl/static/src/utils/utils.js b/awesome_owl/static/src/utils/utils.js index 28d041cc7aa..ad892d4e94e 100644 --- a/awesome_owl/static/src/utils/utils.js +++ b/awesome_owl/static/src/utils/utils.js @@ -1,3 +1,3 @@ export const useAutoFocus = (el) => { el?.focus(); -} \ No newline at end of file +}