Files
owl/doc/reference/utils.md
T

149 lines
4.6 KiB
Markdown
Raw Normal View History

# 🦉 Utils 🦉
2019-05-10 20:50:14 +02:00
Owl export a few useful utility functions, to help with common issues. Those
functions are all available in the `owl.utils` namespace.
## Content
2019-06-11 08:58:37 +02:00
- [`whenReady`](#whenready): executing code when DOM is ready
- [`loadJS`](#loadjs): loading script files
- [`loadFile`](#loadfile): loading a file (useful for templates)
2019-06-11 08:58:37 +02:00
- [`escape`](#escape): sanitizing strings
- [`debounce`](#debounce): limiting rate of function calls
2019-10-17 09:50:03 +02:00
- [`shallowEqual`](#shallowequal): shallow object comparison
2019-05-10 20:50:14 +02:00
## `whenReady`
The function `whenReady` returns a `Promise` resolved when the DOM is ready (if
not ready yet, resolved directly otherwise). If called with a callback as
argument, it executes it as soon as the DOM ready (or directly).
```js
2020-04-21 15:08:53 +02:00
Promise.all([loadFile("templates.xml"), owl.utils.whenReady()]).then(function ([templates]) {
const qweb = new owl.QWeb({ templates });
2020-10-27 14:41:09 +01:00
const env = { qweb };
await mount(App, { env, target: document.body });
});
```
2019-05-10 20:50:14 +02:00
2019-10-17 09:50:03 +02:00
or alternatively:
2019-05-10 20:50:14 +02:00
```js
2020-04-21 15:08:53 +02:00
owl.utils.whenReady(function () {
2019-06-14 15:24:04 +02:00
const qweb = new owl.QWeb();
2020-10-27 14:41:09 +01:00
const env = { qweb };
await mount(App, { env, target: document.body });
2019-05-10 20:50:14 +02:00
});
```
2019-06-11 08:58:37 +02:00
## `loadJS`
2019-05-10 20:50:14 +02:00
`loadJS` takes a url (string) for a javascript resource, and loads it (by adding
a script tag in the document head). It returns 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 prevent doing twice the work.
2019-05-10 20:50:14 +02:00
For example, it is useful for lazy loading external libraries:
2019-10-20 09:01:38 +02:00
2019-06-11 08:58:37 +02:00
```js
class MyComponent extends owl.Component {
2019-06-14 15:24:04 +02:00
willStart() {
return owl.utils.loadJS("/static/libs/someLib.js");
}
2019-06-11 08:58:37 +02:00
}
```
2019-05-10 20:50:14 +02:00
## `loadFile`
2019-05-10 20:50:14 +02:00
2019-10-20 09:01:38 +02:00
`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:
2019-10-17 09:50:03 +02:00
2019-06-11 08:58:37 +02:00
```js
async function makeEnv() {
const templates = await owl.utils.loadFile("templates.xml");
const qweb = new owl.QWeb({ templates });
2019-06-14 15:24:04 +02:00
return { qweb };
2019-06-11 08:58:37 +02:00
}
```
2019-05-10 20:50:14 +02:00
Note that unlike `loadJS`, this function returns the content of the file as a
string. It does not add a `script` tag or any other side effect.
2019-06-11 08:58:37 +02:00
## `escape`
2019-05-10 20:50:14 +02:00
2019-10-17 09:50:03 +02:00
Sometimes, we need to display dynamic data (for example user-generated data) in
2019-10-20 09:01:38 +02:00
the user interface. If this is done by a `QWeb` template, it is not an issue:
2019-10-17 09:50:03 +02:00
```xml
<div><t t-esc="user.data"/></div>
```
The `QWeb` engine will create a `div` node and add the content of the `user.data`
2019-10-20 09:01:38 +02:00
string as a text node, so the web browser will not parse it as html. However,
2019-10-17 09:50:03 +02:00
it may be a problem if this is done with some javascript code like this:
```js
class BadComponent extends Component {
2019-10-20 09:01:38 +02:00
// some template with a ref to a div
// some code ...
2019-10-17 09:50:03 +02:00
2019-10-20 09:01:38 +02:00
mounted() {
this.divRef.el.innerHTML = this.state.value;
}
2019-10-17 09:50:03 +02:00
}
```
2019-10-20 09:01:38 +02:00
2019-10-17 09:50:03 +02:00
In this case, the content of the `div` will be parsed as html, which may inject
2019-10-20 09:01:38 +02:00
unwanted behaviour. To fix this, the `escape` function will simply transform a
2019-10-17 09:50:03 +02:00
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: `"&lt;ok&gt;"`). So, the bad example above can be fixed
with the following change:
```js
2019-10-20 09:01:38 +02:00
this.divRef.el.innerHTML = owl.utils.escape(this.state.value);
2019-10-17 09:50:03 +02:00
```
2019-06-11 08:58:37 +02:00
## `debounce`
2019-10-17 09:50:03 +02:00
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:
2019-10-20 09:01:38 +02:00
2019-10-17 09:50:03 +02:00
- `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
2019-10-20 09:01:38 +02:00
rate limit the function `func`
2019-10-17 09:50:03 +02:00
- `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).
2019-10-20 09:01:38 +02:00
It returns a function. For example:
2019-10-17 09:50:03 +02:00
```js
2019-10-20 09:01:38 +02:00
const debounce = owl.utils.debounce;
window.addEventListener("mousemove", debounce(doSomething, 100));
2019-10-17 09:50:03 +02:00
```
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
2019-10-20 09:01:38 +02:00
shallowEqual({ a: 1, b: 2 }, { a: 1, b: 2 }); // true
shallowEqual({ a: 1, b: 2 }, { a: 1, b: 3 }); // false
2019-10-17 09:50:03 +02:00
```
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
2019-10-20 09:01:38 +02:00
const completeShallowEqual = (a, b) => shallowEqual(a, b) && shallowEqual(b, a);
```