mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[DOC] update the documentation
closes #334 closes #336 closes #338 closes #339 closes #341 closes #342 closes #343 closes #346 closes #348
This commit is contained in:
+4
-5
@@ -30,7 +30,7 @@ btn {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
will produce a nice flash effect whenever the user click (or activate with the
|
will produce a nice flash effect whenever the user clicks (or activates with the
|
||||||
keyboard) the button.
|
keyboard) the button.
|
||||||
|
|
||||||
## CSS Transitions
|
## CSS Transitions
|
||||||
@@ -47,7 +47,7 @@ the lifetime of a node. Since this is not easy to do by hand, Owl `t-transition`
|
|||||||
directive is there to help.
|
directive is there to help.
|
||||||
|
|
||||||
Whenever a node has a `t-transition` directive, with a `name` value, the following
|
Whenever a node has a `t-transition` directive, with a `name` value, the following
|
||||||
will happen:
|
sequence of events will happen:
|
||||||
|
|
||||||
At node insertion:
|
At node insertion:
|
||||||
|
|
||||||
@@ -91,6 +91,5 @@ The `t-transition` directive can be applied on a node element or on a component.
|
|||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
- more information on animations are available [here](animations.md).
|
Owl does not support more than one transition on a single node, so the
|
||||||
- Owl does not support more than one transition on a single node, so the
|
`t-transition` expression must be a single value (i.e. no space allowed).
|
||||||
`t-transition` expression must be a single value (i.e. no space allowed)
|
|
||||||
|
|||||||
+87
-21
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
OWL components are the building blocks for user interface. They are designed to be:
|
OWL components are the building blocks for user interface. They are designed to be:
|
||||||
|
|
||||||
1. **declarative:** the user interface should be described in term of the state
|
1. **declarative:** the user interface should be described in terms of the state
|
||||||
of the application, not as a sequence of imperative steps.
|
of the application, not as a sequence of imperative steps.
|
||||||
|
|
||||||
2. **composable:** each component can seamlessly be created in a parent component by
|
2. **composable:** each component can seamlessly be created in a parent component by
|
||||||
@@ -72,7 +72,7 @@ class ClickCounter extends owl.Component {
|
|||||||
Note that this code is written in ESNext style, so it will only run on the
|
Note that this code is written in ESNext style, so it will only run on the
|
||||||
latest browsers without a transpilation step.
|
latest browsers without a transpilation step.
|
||||||
|
|
||||||
This example show how a component should be defined: it simply subclasses the
|
This example shows how a component should be defined: it simply subclasses the
|
||||||
Component class. If no static `template` key is defined, then
|
Component class. If no static `template` key is defined, then
|
||||||
Owl will use the component's name as template name. Here,
|
Owl will use the component's name as template name. Here,
|
||||||
a state object is defined, by using the `useState` hook. It is not mandatory to use the state object, but it is certainly encouraged. The result of the `useState` call is
|
a state object is defined, by using the `useState` hook. It is not mandatory to use the state object, but it is certainly encouraged. The result of the `useState` call is
|
||||||
@@ -80,33 +80,86 @@ a state object is defined, by using the `useState` hook. It is not mandatory to
|
|||||||
|
|
||||||
## Reference
|
## Reference
|
||||||
|
|
||||||
An Owl component is a small class which represent a component or some UI element.
|
An Owl component is a small class which represents a component or some UI element.
|
||||||
It exists in the context of an environment (`env`), which is propagated from a
|
It exists in the context of an environment (`env`), which is propagated from a
|
||||||
parent to its children. The environment needs to have a QWeb instance, which
|
parent to its children. The environment needs to have a QWeb instance, which
|
||||||
will be used to render the component template.
|
will be used to render the component template.
|
||||||
|
|
||||||
Be aware that the name of the component may be significant: if a component does
|
Be aware that the name of the component may be significant: if a component does
|
||||||
not define a `template` key, then Owl will lookup in QWeb to
|
not define a `template` key, then Owl will lookup in QWeb to
|
||||||
find a template with the component name (or one of its ancestor).
|
find a template with the component name (or one of its ancestors).
|
||||||
|
|
||||||
### Reactive system
|
### Reactive system
|
||||||
|
|
||||||
OWL components can be made reactive by observing some part of their state. See the [hooks](hooks.md) section for more details.
|
OWL components are normal javascript classes. So, changing a component internal
|
||||||
|
state does nothing more:
|
||||||
|
|
||||||
The main idea is that the `useState` hook generate a proxy version of an object
|
```js
|
||||||
(this is done by an [observer](observer.md)), which allows the component to
|
class Counter extends Component {
|
||||||
react to any change.
|
static template = xml`<div t-on-click="increment"><t t-esc="state.value"/></div>`;
|
||||||
|
state = {value: 0};
|
||||||
|
|
||||||
```javascript
|
increment() {
|
||||||
const { useState } = owl.hooks;
|
this.state.value++;
|
||||||
|
}
|
||||||
class SomeComponent extends owl.Component {
|
|
||||||
state = useState({ a: 0, b: 1 });
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that there is an important limitation: hooks need to be called in the
|
Clicking on the `Counter` component defined above will call the `increment`
|
||||||
constructor.
|
method, but it will not rerender the component. To fix that, one could add an
|
||||||
|
explicit call to `render` in `increment`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
increment() {
|
||||||
|
this.state.value++;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
However, it may be simple in this case, but it quickly become cumbersome, as a
|
||||||
|
component get more complex, and its internal state is modified by more than one
|
||||||
|
method.
|
||||||
|
|
||||||
|
A better way is to use the reactive system: by using the `useState` hook (see the
|
||||||
|
[hooks](hooks.md) section for more details), one can make Owl react to state
|
||||||
|
changes. The `useState` hook generates a proxy version of an object
|
||||||
|
(this is done by an [observer](observer.md)), which allows the component to
|
||||||
|
react to any change. So, the `Counter` example above can be improved like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { useState } = owl.hooks;
|
||||||
|
|
||||||
|
class Counter extends Component {
|
||||||
|
static template = xml`<div t-on-click="increment"><t t-esc="state.value"/></div>`;
|
||||||
|
state = useState({value: 0});
|
||||||
|
|
||||||
|
increment() {
|
||||||
|
this.state.value++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Obviously, we can call the `useState` hook more than once:
|
||||||
|
```js
|
||||||
|
const { useState } = owl.hooks;
|
||||||
|
|
||||||
|
class Counter extends Component {
|
||||||
|
static template = xml`
|
||||||
|
<div>
|
||||||
|
<span t-on-click="increment(counter1)"><t t-esc="counter1.value"/></span>
|
||||||
|
<span t-on-click="increment(counter2)"><t t-esc="counter2.value"/></span>
|
||||||
|
</div>`;
|
||||||
|
counter1 = useState({value: 0});
|
||||||
|
counter2 = useState({value: 0});
|
||||||
|
|
||||||
|
increment(counter) {
|
||||||
|
counter.value++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that hooks are subject to one important [rule](hooks.md#one-rule): they need
|
||||||
|
to be called in the constructor.
|
||||||
|
|
||||||
### Properties
|
### Properties
|
||||||
|
|
||||||
@@ -115,10 +168,23 @@ constructor.
|
|||||||
|
|
||||||
- **`env`** (Object): the component environment, which contains a QWeb instance.
|
- **`env`** (Object): the component environment, which contains a QWeb instance.
|
||||||
|
|
||||||
- **`props`** (Object): this is an object given (in the constructor) by the parent
|
- **`props`** (Object): this is an object containing all the properties given by
|
||||||
to configure the component. It can be dynamically changed later by the parent,
|
the parent to a child component. For example, in the following situation,
|
||||||
in some case. Note that `props` are owned by the parent, not by the component.
|
the parent component gives a `user` and a `color` value to the `ChildComponent`.
|
||||||
As such, it should not ever be modified by the component!!
|
|
||||||
|
```xml
|
||||||
|
<div>
|
||||||
|
<ChildComponent user="state.user" color="color">
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that `props` are owned by the parent, not by the component.
|
||||||
|
As such, it should not ever be modified by the component (otherwise you risk
|
||||||
|
unintended effects, since the parent may not be aware of the change)!!
|
||||||
|
|
||||||
|
The `props` can be modified dynamically by the parent. In that case, the
|
||||||
|
component will go through the following lifecycle methods: `willUpdateProps`,
|
||||||
|
`willPatch` and `patched`.
|
||||||
|
|
||||||
### Static Properties
|
### Static Properties
|
||||||
|
|
||||||
@@ -182,7 +248,7 @@ We explain here all the public methods of the `Component` class.
|
|||||||
we know that its state (or something in the environment, or ...) has changed.
|
we know that its state (or something in the environment, or ...) has changed.
|
||||||
In that case, it should simply set to `true`.
|
In that case, it should simply set to `true`.
|
||||||
|
|
||||||
- **`unmount()`**: in case a component need to be detached/removed from the DOM, this
|
- **`unmount()`**: in case a component needs to be detached/removed from the DOM, this
|
||||||
method can be used. Most applications should not call `unmount`, this is more
|
method can be used. Most applications should not call `unmount`, this is more
|
||||||
useful to the underlying component system.
|
useful to the underlying component system.
|
||||||
|
|
||||||
@@ -338,7 +404,7 @@ with the DOM (for example, through an external library) whenever the
|
|||||||
component was patched. Note that this hook will not be called if the compoent is
|
component was patched. Note that this hook will not be called if the compoent is
|
||||||
not in the DOM (this can happen with components with `t-keepalive`).
|
not in the DOM (this can happen with components with `t-keepalive`).
|
||||||
|
|
||||||
Updating the compoent state in this hook is possible, but not encouraged.
|
Updating the component state in this hook is possible, but not encouraged.
|
||||||
One need to be careful, because updates here will cause rerender, which in
|
One need to be careful, because updates here will cause rerender, which in
|
||||||
turn will cause other calls to patched. So, we need to be particularly
|
turn will cause other calls to patched. So, we need to be particularly
|
||||||
careful at avoiding endless cycles.
|
careful at avoiding endless cycles.
|
||||||
|
|||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
# 🦉 Observer 🦉
|
# 🦉 Observer 🦉
|
||||||
|
|
||||||
Owl need to be able to react to state changes. For example, whenever the state
|
Owl needs to be able to react to state changes. For example, whenever the state
|
||||||
of a component is changed, we need to rerender it. To help with that, we have
|
of a component is changed, we need to rerender it. To help with that, we have
|
||||||
an Observer class. Its job is to observe some object state, and react to any
|
an Observer class. Its job is to observe some object state, and react to any
|
||||||
change. To do that, it recursively replace all keys of the observed state by
|
change. To do that, it recursively replaces all keys of the observed state by
|
||||||
getters and setters.
|
getters and setters.
|
||||||
|
|
||||||
For example, this code will display `update` in the console:
|
For example, this code will display `update` in the console:
|
||||||
|
|||||||
+2
-5
@@ -55,7 +55,7 @@ To build an application (or a sub-part of an application), we need two things:
|
|||||||
|
|
||||||
- an environment: it is the global context in which we are working. It needs to
|
- an environment: it is the global context in which we are working. It needs to
|
||||||
contain a QWeb instance (preloaded with templates), and anything else that we
|
contain a QWeb instance (preloaded with templates), and anything else that we
|
||||||
need. In practice, it could context some user session information, some
|
need. In practice, it could be used to contain some user session information, some
|
||||||
configuration keys (for example, isMobile = true/false if we are in mobile mode).
|
configuration keys (for example, isMobile = true/false if we are in mobile mode).
|
||||||
|
|
||||||
- a description of the user interface: there should be a root component, which can
|
- a description of the user interface: there should be a root component, which can
|
||||||
@@ -76,10 +76,7 @@ const useState = owl.hooks.useState;
|
|||||||
|
|
||||||
class ClickCounter extends owl.Component {
|
class ClickCounter extends owl.Component {
|
||||||
static template = "clickcounter";
|
static template = "clickcounter";
|
||||||
constructor() {
|
state = useState({ value: 0 });
|
||||||
super(...arguments);
|
|
||||||
this.state = useState({ value: 0 });
|
|
||||||
}
|
|
||||||
|
|
||||||
increment() {
|
increment() {
|
||||||
this.state.value++;
|
this.state.value++;
|
||||||
|
|||||||
+17
-17
@@ -17,12 +17,12 @@
|
|||||||
|
|
||||||
Managing the state in an application is not an easy task. In some cases, the
|
Managing the state in an application is not an easy task. In some cases, the
|
||||||
state of an application can be part of the component tree, in a natural way.
|
state of an application can be part of the component tree, in a natural way.
|
||||||
However, there are situations where some part of the state need to be displayed
|
However, there are situations where some parts of the state need to be displayed
|
||||||
in various parts of the user interface, and then, it is not obvious which
|
in various parts of the user interface, and then, it is not obvious which
|
||||||
component should own which part of the state.
|
component should own which part of the state.
|
||||||
|
|
||||||
Owl's solution to this issue is a centralized store. It is a class that owns
|
Owl's solution to this issue is a centralized store. It is a class that owns
|
||||||
some (or all) state, and let the developer update it in a structured way, with
|
some (or all) state, and lets the developer update it in a structured way, with
|
||||||
`actions`. Owl components can then connect to the store, and will be updated if
|
`actions`. Owl components can then connect to the store, and will be updated if
|
||||||
necessary.
|
necessary.
|
||||||
|
|
||||||
@@ -38,14 +38,14 @@ const actions = {
|
|||||||
state.todos.push({
|
state.todos.push({
|
||||||
id: state.nextId++,
|
id: state.nextId++,
|
||||||
message,
|
message,
|
||||||
isCompleted: false
|
isCompleted: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
todos: [],
|
todos: [],
|
||||||
nextId: 1
|
nextId: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
const store = new owl.Store({ state, actions });
|
const store = new owl.Store({ state, actions });
|
||||||
@@ -115,7 +115,7 @@ const actions = {
|
|||||||
The first argument to an action method is an object with four keys:
|
The first argument to an action method is an object with four keys:
|
||||||
- `state`: the current state of the store content,
|
- `state`: the current state of the store content,
|
||||||
- `dispatch`: a function that can be used to dispatch other actions,
|
- `dispatch`: a function that can be used to dispatch other actions,
|
||||||
- `getters`: an object containing all getters defined in the store
|
- `getters`: an object containing all getters defined in the store,
|
||||||
- `env`: the current environment. This is useful sometimes, in particular if
|
- `env`: the current environment. This is useful sometimes, in particular if
|
||||||
an action needs to apply some side effects (such as performing an rpc), and
|
an action needs to apply some side effects (such as performing an rpc), and
|
||||||
the `rpc` method is located in the environment.
|
the `rpc` method is located in the environment.
|
||||||
@@ -132,7 +132,7 @@ call.
|
|||||||
|
|
||||||
Also, it is important to be aware that we need to be careful with asynchronous
|
Also, it is important to be aware that we need to be careful with asynchronous
|
||||||
logic. Each state change will potentially trigger a rerendering, so we need to
|
logic. Each state change will potentially trigger a rerendering, so we need to
|
||||||
make sure that we do not have a partial corrupted state. Here is an example that
|
make sure that we do not have a partially corrupted state. Here is an example that
|
||||||
is likely not a good idea:
|
is likely not a good idea:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@@ -185,7 +185,7 @@ transform the data contained in the store.
|
|||||||
const getters = {
|
const getters = {
|
||||||
getPost({ state }, id) {
|
getPost({ state }, id) {
|
||||||
const post = state.posts.find(p => p.id === id);
|
const post = state.posts.find(p => p.id === id);
|
||||||
const author = state.authors.find(a => (a.id = post.id));
|
const author = state.authors.find(a => a.id === post.id);
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
author,
|
author,
|
||||||
@@ -209,7 +209,7 @@ At some point, we need a way to interact with the store from a component. This
|
|||||||
can be done with the help of the three store hooks:
|
can be done with the help of the three store hooks:
|
||||||
|
|
||||||
- `useStore` to subscribe a component to some part of the store state,
|
- `useStore` to subscribe a component to some part of the store state,
|
||||||
- `useDispatch` to get a reference to a dispatch function
|
- `useDispatch` to get a reference to a dispatch function,
|
||||||
- `useGetters` to get a reference to the getters defined in the store.
|
- `useGetters` to get a reference to the getters defined in the store.
|
||||||
|
|
||||||
|
|
||||||
@@ -252,14 +252,14 @@ two arguments:
|
|||||||
|
|
||||||
- a selector function, which takes the store state as first argument (and the
|
- a selector function, which takes the store state as first argument (and the
|
||||||
component props as second argument) and returns
|
component props as second argument) and returns
|
||||||
an object or an array (which will be then observed)
|
an object or an array (which will be then observed),
|
||||||
- optionally, an object with a `store` key (if we want to override the default
|
- optionally, an object with a `store` key (if we want to override the default
|
||||||
store) and an equality function (if we want to specialize the comparison)
|
store) and an equality function (if we want to specialize the comparison).
|
||||||
|
|
||||||
|
|
||||||
If the `useStore` callback selects a sub part of the store state, the component
|
If the `useStore` callback selects a sub part of the store state, the component
|
||||||
will only be rerendered whenever this part of the state changes. Otherwise, it
|
will only be rerendered whenever this part of the state changes. Otherwise, it
|
||||||
will perform a strict equality check and updates the component every time this
|
will perform a strict equality check and will update the component every time this
|
||||||
check fails.
|
check fails.
|
||||||
|
|
||||||
### Semantics
|
### Semantics
|
||||||
@@ -268,23 +268,23 @@ The `Store` class and the `useStore` hook try to be smart and to optimize as muc
|
|||||||
as possible the rendering and update process. What is important to know is:
|
as possible the rendering and update process. What is important to know is:
|
||||||
|
|
||||||
- components are always updated in the order of their creation (so, parent
|
- components are always updated in the order of their creation (so, parent
|
||||||
before children)
|
before children),
|
||||||
- they are updated only if they are in the DOM
|
- they are updated only if they are in the DOM,
|
||||||
- if a parent is asynchronous, the system will wait for it to complete its
|
- if a parent is asynchronous, the system will wait for it to complete its
|
||||||
update before updating other components.
|
update before updating other components,
|
||||||
- in general, updates are not coordinated. This is not a problem for synchronous
|
- in general, updates are not coordinated. This is not a problem for synchronous
|
||||||
components, but if there are many asynchronous components, this could lead to
|
components, but if there are many asynchronous components, this could lead to
|
||||||
a situation where some part of the UI is updated and other parts of the UI is
|
a situation where some part of the UI is updated and some other part of the UI is
|
||||||
not updated.
|
not updated.
|
||||||
|
|
||||||
### Good Practices
|
### Good Practices
|
||||||
|
|
||||||
- avoid asynchronous components as much as possible. Asynchronous components
|
- avoid asynchronous components as much as possible. Asynchronous components
|
||||||
lead to situations where parts of the UI is not updated immediately.
|
lead to situations where parts of the UI is not updated immediately,
|
||||||
- do not be afraid to connect many components, parent or children if needed. For
|
- do not be afraid to connect many components, parent or children if needed. For
|
||||||
example, a `MessageList` component could get a list of ids in its `useStore`
|
example, a `MessageList` component could get a list of ids in its `useStore`
|
||||||
call and a `Message` component could get the data of its own
|
call and a `Message` component could get the data of its own
|
||||||
message
|
message,
|
||||||
- since the `useStore` function is called for each connected component,
|
- since the `useStore` function is called for each connected component,
|
||||||
for each state update, it is important to make sure that these functions are
|
for each state update, it is important to make sure that these functions are
|
||||||
as fast as possible.
|
as fast as possible.
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# 🦉 Tags 🦉
|
# 🦉 Tags 🦉
|
||||||
|
|
||||||
Tags are very small helper to make it easy to write inline templates. There is
|
Tags are very small helpers to make it easy to write inline templates. There is
|
||||||
only one currently available tag: `xml`, but we plan to add other tags later,
|
only one currently available tag: `xml`, but we plan to add other tags later,
|
||||||
such as a `css` tag, which will be used to write single file components.
|
such as a `css` tag, which will be used to write single file components.
|
||||||
|
|
||||||
|
|||||||
+82
-1
@@ -10,6 +10,8 @@ functions are all available in the `owl.utils` namespace.
|
|||||||
- [`loadTemplates`](#loadtemplates): loading xml files
|
- [`loadTemplates`](#loadtemplates): loading xml files
|
||||||
- [`escape`](#escape): sanitizing strings
|
- [`escape`](#escape): sanitizing strings
|
||||||
- [`debounce`](#debounce): limiting rate of function calls
|
- [`debounce`](#debounce): limiting rate of function calls
|
||||||
|
- [`shallowEqual`](#shallowequal): shallow object comparison
|
||||||
|
|
||||||
|
|
||||||
## `whenReady`
|
## `whenReady`
|
||||||
|
|
||||||
@@ -25,6 +27,8 @@ Promise.all([loadTemplates(), owl.utils.whenReady()]).then(function([templates])
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
or alternatively:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
owl.utils.whenReady(function() {
|
owl.utils.whenReady(function() {
|
||||||
const qweb = new owl.QWeb();
|
const qweb = new owl.QWeb();
|
||||||
@@ -36,7 +40,7 @@ owl.utils.whenReady(function() {
|
|||||||
## `loadJS`
|
## `loadJS`
|
||||||
|
|
||||||
`loadJS` takes a url (string) for a javascript resource, and loads it. It returns
|
`loadJS` takes a url (string) for a javascript resource, and loads it. It returns
|
||||||
a promise, so the caller can properly react when it is ready. Also, it is smart:
|
a promise, so the caller can properly reacts when it is ready. Also, it is smart:
|
||||||
it maintains a list of urls previously loaded (or currently being loaded), and
|
it maintains a list of urls previously loaded (or currently being loaded), and
|
||||||
prevent doing twice the work.
|
prevent doing twice the work.
|
||||||
|
|
||||||
@@ -50,6 +54,10 @@ class MyComponent extends owl.Component {
|
|||||||
|
|
||||||
## `loadTemplates`
|
## `loadTemplates`
|
||||||
|
|
||||||
|
`loadTemplates` is a helper function to fetch a template file. It simply
|
||||||
|
performs a `GET` request and return the resulting string in a promise. For
|
||||||
|
example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async function makeEnv() {
|
async function makeEnv() {
|
||||||
const templates = await owl.utils.loadTemplates("templates.xml");
|
const templates = await owl.utils.loadTemplates("templates.xml");
|
||||||
@@ -60,4 +68,77 @@ async function makeEnv() {
|
|||||||
|
|
||||||
## `escape`
|
## `escape`
|
||||||
|
|
||||||
|
Sometimes, we need to display dynamic data (for example user-generated data) in
|
||||||
|
the user interface. If this is done by a `QWeb` template, it is not an issue:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div><t t-esc="user.data"/></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
The `QWeb` engine will create a `div` node and add the content of the `user.data`
|
||||||
|
string as a text node, so the web browser will not parse it as html. However,
|
||||||
|
it may be a problem if this is done with some javascript code like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
class BadComponent extends Component {
|
||||||
|
// some template with a ref to a div
|
||||||
|
// some code ...
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.divRef.el.innerHTML = this.state.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
In this case, the content of the `div` will be parsed as html, which may inject
|
||||||
|
unwanted behaviour. To fix this, the `escape` function will simply transform a
|
||||||
|
string into an escaped version of the same string, which will be properly displayed
|
||||||
|
by the browser, but which will not be parsed as html (for example, `"<ok>"` is
|
||||||
|
escaped to the string: `"<ok>"`). So, the bad example above can be fixed
|
||||||
|
with the following change:
|
||||||
|
|
||||||
|
```js
|
||||||
|
this.divRef.el.innerHTML = owl.utils.escape(this.state.value);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## `debounce`
|
## `debounce`
|
||||||
|
|
||||||
|
The `debounce` function is useful when we want to limit the number of times some
|
||||||
|
function/action is perfomed. For example, this may be useful to prevent issue
|
||||||
|
with people double clicking on a button.
|
||||||
|
|
||||||
|
It takes three arguments:
|
||||||
|
- `func` (function): this is the function that will be rate limited
|
||||||
|
- `wait` (number): this is the number of milliseconds that we want to use to
|
||||||
|
rate limit the function `func`
|
||||||
|
- `immediate` (optional, boolean, default=false): if `immediate` is true, the
|
||||||
|
function will be triggered immediately (leading edge of the interval). If false,
|
||||||
|
the function will be triggered at the end (trailing edge).
|
||||||
|
|
||||||
|
It returns a function. For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const debounce = owl.utils.debounce
|
||||||
|
window.addEventListener('mousemove', debounce(doSomething, 100));
|
||||||
|
```
|
||||||
|
|
||||||
|
As this example shows, it is usualy useful for event handlers which are triggered
|
||||||
|
very quickly, such as `scroll` or `mousemove` events.
|
||||||
|
|
||||||
|
|
||||||
|
## `shallowEqual`
|
||||||
|
|
||||||
|
This function checks if two objects have the same values assigned to each keys:
|
||||||
|
|
||||||
|
```js
|
||||||
|
shallowEqual({a:1, b: 2}, {a:1, b:2}); // true
|
||||||
|
shallowEqual({a:1, b: 2}, {a:1, b:3}); // false
|
||||||
|
```
|
||||||
|
|
||||||
|
However, for performance reasons, it assumes that the two objects have the same
|
||||||
|
keys. If we are in a situation where this is not guaranteed, the following code
|
||||||
|
will work:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const completeShallowEqual = (a,b) => shallowEqual(a,b) && shallowEqual(b,a);
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user