Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 0 additions & 47 deletions .eslintrc

This file was deleted.

46 changes: 26 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![npm version](https://badge.fury.io/js/@odoo%2Fowl.svg)](https://badge.fury.io/js/@odoo%2Fowl)
[![Downloads](https://img.shields.io/npm/dm/@odoo%2Fowl.svg)](https://www.npmjs.com/package/@odoo/owl)

_Class based components with hooks, reactive state and concurrent mode_
_Class based components with hooks, signals and concurrent mode_

**Try it online!** you can experiment with the Owl framework in an online [playground](https://odoo.github.io/owl/playground).

Expand All @@ -16,9 +16,10 @@ framework, written in Typescript, taking the best ideas from React and Vue in a
simple and consistent way. Owl's main features are:

- a declarative component system,
- a fine grained reactivity system similar to Vue,
- hooks
- fragments
- a signal-based reactivity system (signals, computed values, effects),
- a plugin system for sharing state and services,
- hooks,
- fragments,
- asynchronous rendering

Owl components are defined with ES6 classes and xml templates, uses an
Expand All @@ -29,44 +30,52 @@ Quick links:

- [documentation](#documentation),
- [changelog](CHANGELOG.md) (from Owl 1.x to 2.x),
- [Owl 3.x release notes](release_notes.md) (draft),
- [playground](https://odoo.github.io/owl/playground)

## Example

Here is a short example to illustrate interactive components:

```javascript
const { Component, useState, mount, xml } = owl;
const { Component, signal, mount, xml } = owl;

class Counter extends Component {
static template = xml`
<button t-on-click="() => state.value = state.value + props.increment">
Click Me! [<t t-esc="state.value"/>]
<button t-on-click="this.increment">
Click Me! [<t t-out="this.count()"/>]
</button>`;

state = useState({ value: 0 });
count = signal(0);

increment() {
this.count.set(this.count() + 1);
}
}

class Root extends Component {
static template = xml`
<span>Hello Owl</span>
<Counter increment="2"/>`;
<Counter/>`;

static components = { Counter };
}

mount(Root, document.body);
```

Note that the counter component is made reactive with the [`useState` hook](doc/reference/hooks.md#usestate).
Also, all examples here uses the [`xml` helper](doc/reference/templates.md#inline-templates) to define inline templates.
Note that the counter component is made reactive with a [`signal`](release_notes.md#signals).
Also, all examples here use the `xml` helper to define inline templates.
But this is not mandatory, many applications will load templates separately.

More interesting examples can be found on the
[playground](https://odoo.github.io/owl/playground) application.

## Documentation

Note: the reference documentation below was written for Owl 2.x. The
[Owl 3.x release notes](release_notes.md) describe all changes in detail.

### Learning Owl

Are you new to Owl? This is the place to start!
Expand All @@ -84,15 +93,13 @@ Are you new to Owl? This is the place to start!
- [Concurrency Model](doc/reference/concurrency_model.md)
- [Dev mode](doc/reference/app.md#dev-mode)
- [Dynamic sub components](doc/reference/component.md#dynamic-sub-components)
- [Environment](doc/reference/environment.md)
- [Error Handling](doc/reference/error_handling.md)
- [Event Handling](doc/reference/event_handling.md)
- [Form Input Bindings](doc/reference/input_bindings.md)
- [Fragments](doc/reference/templates.md#fragments)
- [Hooks](doc/reference/hooks.md)
- [Loading Templates](doc/reference/app.md#loading-templates)
- [Mounting a component](doc/reference/app.md#mount-helper)
- [Portal](doc/reference/portal.md)
- [Precompiling templates](doc/reference/precompiling_templates.md)
- [Props](doc/reference/props.md)
- [Props Validation](doc/reference/props.md#props-validation)
Expand All @@ -112,6 +119,7 @@ Are you new to Owl? This is the place to start!
- [Comparison with React/Vue](doc/miscellaneous/comparison.md)
- [Why did Odoo build Owl?](doc/miscellaneous/why_owl.md)
- [Changelog (from owl 1.x to 2.x)](CHANGELOG.md)
- [Owl 3.x Release Notes (draft)](release_notes.md)
- [Notes on compiled templates](doc/miscellaneous/compiled_template.md)
- [Owl devtools extension](doc/tools/devtools.md)

Expand All @@ -134,16 +142,14 @@ Unzip the owl-devtools.zip file and follow the instructions depending on your br
### Chrome

Go to your chrome extensions admin panel, activate developer mode and click on `Load unpacked`.
Select the devtools-chrome folder and that's it, your extension is active!
There is a convenient refresh button on the extension card (still on the same admin page) to update your code.
Do note that if you got some problems, you may need to completly remove and reload the extension to completly refresh the extension.
Select the devtools-chrome folder and that's it, your extension is active!
There is a convenient refresh button on the extension card (still on the same admin page) to update your code.
Do note that if you have problems, you may need to completely remove and reload the extension to fully refresh it.

### Firefox
### Firefox
Go to the address about:debugging#/runtime/this-firefox and click on `Load temporary Add-on...`.
Select any file in the devtools-firefox folder and that's it, your extension is active!
Select any file in the devtools-firefox folder and that's it, your extension is active!
Here, you can use the reload button to refresh the extension.

Note that you may have to open another window or reload your tab to see the extension working.
Also note that the extension will only be active on pages that have a sufficient version of owl.


10 changes: 5 additions & 5 deletions doc/learning/tutorial_todoapp.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ data and a template to the `App` component:

```js
class Root extends Component {
static template = xml/* xml */ `
static template = xml /* xml */ `
<div class="task-list">
<t t-foreach="tasks" t-as="task" t-key="task.id">
<div class="task">
Expand Down Expand Up @@ -565,7 +565,7 @@ function createTaskStore() {
// Task Component
// -------------------------------------------------------------------------
class Task extends Component {
static template = xml/* xml */ `
static template = xml /* xml */ `
<div class="task" t-att-class="props.task.isCompleted ? 'done' : ''">
<input type="checkbox" t-att-checked="props.task.isCompleted" t-on-click="() => store.toggleTask(props.task)"/>
<span><t t-esc="props.task.text"/></span>
Expand All @@ -583,7 +583,7 @@ class Task extends Component {
// Root Component
// -------------------------------------------------------------------------
class Root extends Component {
static template = xml/* xml */ `
static template = xml /* xml */ `
<div class="todo-app">
<input placeholder="Enter a new task" t-on-keyup="addTask" t-ref="add-input"/>
<div class="task-list">
Expand Down Expand Up @@ -838,7 +838,7 @@ For reference, here is the final code:
// Task Component
// -------------------------------------------------------------------------
class Task extends Component {
static template = xml/* xml */ `
static template = xml /* xml */ `
<div class="task" t-att-class="props.task.isCompleted ? 'done' : ''">
<input type="checkbox"
t-att-id="props.task.id"
Expand All @@ -859,7 +859,7 @@ For reference, here is the final code:
// Root Component
// -------------------------------------------------------------------------
class Root extends Component {
static template = xml/* xml */ `
static template = xml /* xml */ `
<div class="todo-app">
<input placeholder="Enter a new task" t-on-keyup="addTask" t-ref="add-input"/>
<div class="task-list">
Expand Down
3 changes: 1 addition & 2 deletions doc/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,14 @@ Other hooks:
- [`useComponent`](reference/hooks.md#usecomponent): return a reference to the current component (useful to create derived hooks)
- [`useEffect`](reference/hooks.md#useeffect): define an effect with its dependencies
- [`useEnv`](reference/hooks.md#useenv): return a reference to the current env
- [`useExternalListener`](reference/hooks.md#useexternallistener): add a listener outside of a component DOM
- [`useListener`](reference/hooks.md#uselistener): add a listener outside of a component DOM
- [`useRef`](reference/hooks.md#useref): get an object representing a reference (`t-ref`)
- [`useChildSubEnv`](reference/hooks.md#usesubenv-and-usechildsubenv): extend the current env with additional information (for child components)
- [`useSubEnv`](reference/hooks.md#usesubenv-and-usechildsubenv): extend the current env with additional information (for current component and child components)

Utility/helpers:

- [`EventBus`](reference/utils.md#eventbus): a simple event bus
- [`loadFile`](reference/utils.md#loadfile): an helper to load a file from the server
- [`markup`](reference/templates.md#outputting-data): utility function to define strings that represent html (should not be escaped)
- [`status`](reference/component.md#status-helper): utility function to get the status of a component (new, mounted or destroyed)
- [`validate`](reference/utils.md#validate): validates if an object satisfies a specified schema
Expand Down
3 changes: 1 addition & 2 deletions doc/reference/app.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ instance somewhere in the DOM.
is complete.

The `option` object is an object with the following keys:

- **`position (string)`**: either `first-child` or `last-child`. This option determines
the position of the application in the target: either first or last child.

Expand Down Expand Up @@ -130,7 +129,7 @@ what it could look like in practice:

```js
// in the main js file:
const { loadFile, mount } = owl;
const { mount } = owl;

// async, so we can use async/await
(async function setup() {
Expand Down
3 changes: 0 additions & 3 deletions doc/reference/concurrency_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ component (with some code like `app.mount(document.body)`).
1. `willStart` is called on `A`

2. when it is done, template `A` is rendered.

- component `B` is created
1. `willStart` is called on `B`
2. template `B` is rendered
Expand Down Expand Up @@ -116,7 +115,6 @@ Here is what Owl will do:

1. because of a state change, the method `render` is called on `C`
2. template `C` is rendered again

- component `D` is updated:
1. hook `willUpdateProps` is called on `D` (async)
2. template `D` is rerendered
Expand All @@ -130,7 +128,6 @@ Here is what Owl will do:
4. components `F`, `D` are patched in that order

5. component `C` is patched, which will cause recursively:

1. `willUnmount` hook on `E`
2. destruction of `E`,

Expand Down
8 changes: 4 additions & 4 deletions doc/reference/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
- [`useState`](#usestate)
- [`useRef`](#useref)
- [`useSubEnv` and `useChildSubEnv`](#usesubenv-and-usechildsubenv)
- [`useExternalListener`](#useexternallistener)
- [`useListener`](#uselistener)
- [`useComponent`](#usecomponent)
- [`useEnv`](#useenv)
- [`useEffect`](#useeffect)
Expand Down Expand Up @@ -187,16 +187,16 @@ frozen, to prevent unwanted modifications.
Note that both these hooks can be called an arbitrary number of times. The `env`
will then be updated accordingly.

### `useExternalListener`
### `useListener`

The `useExternalListener` hook helps solve a very common problem: adding and removing
The `useListener` hook helps solve a very common problem: adding and removing
a listener on some target whenever a component is mounted/unmounted. It takes a target
as its first argument, forwards the other arguments to `addEventListener`. For example,
a dropdown menu (or its parent) may need to listen to a `click` event on `window`
to be closed:

```js
useExternalListener(window, "click", this.closeMenu, { capture: true });
useListener(window, "click", this.closeMenu, { capture: true });
```

### `useComponent`
Expand Down
16 changes: 0 additions & 16 deletions doc/reference/utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ functions are all available in the `owl.utils` namespace.
## Content

- [`whenReady`](#whenready): executing code when DOM is ready
- [`loadFile`](#loadfile): loading a file (useful for templates)
- [`EventBus`](#eventbus): a simple EventBus
- [`validate`](#validate): a validation function
- [`batched`](#batched): batch function calls
Expand All @@ -32,21 +31,6 @@ whenReady(function () {
});
```

## `loadFile`

`loadFile` is a helper function to fetch a file. It simply
performs a `GET` request and returns the resulting string in a promise. The
initial usecase for this function is to load a template file. For example:

```js
const { loadFile } = owl;

async function makeEnv() {
const templates = await loadFile("templates.xml");
// do something
}
```

## `EventBus`

It is a simple `EventBus`, with the same API as usual DOM elements, and an
Expand Down
Loading