2021-10-31 17:40:36 +07:00
2021-11-05 14:33:19 +07:00
.. _frontend/services:
2021-10-31 17:40:36 +07:00
2021-10-18 15:48:07 +07:00
========
Services
========
Services are long lived pieces of code that provide a feature. They may be
imported by components (with `` useService `` ) or by other services. Also, they
can declare a set of dependencies. In that sense, services are basically a
DI :dfn: `dependency injection` system. For example, the `` notification `` service
provides a way to display a notification, or the `` rpc `` service is the proper
way to perform a request to the Odoo server.
The following example registers a simple service that displays a notification
every 5 seconds:
.. code-block :: javascript
2021-10-31 17:40:36 +07:00
import { registry } from "@web/core/registry";
2021-10-18 15:48:07 +07:00
const myService = {
dependencies: ["notification"],
start(env, { notification }) {
let counter = 1;
setInterval(() => {
notification.add(`Tick Tock ${counter++}` );
}, 5000);
}
};
2021-10-31 17:40:36 +07:00
registry.category("services").add("myService", myService);
2021-10-18 15:48:07 +07:00
2021-10-21 16:46:30 +07:00
At startup, the web client starts all services present in the `services`
registry. Note that the name used in the registry is the name of the service.
2021-10-18 15:48:07 +07:00
.. note ::
Most code that is not a component should be *packaged* in a service, in
particular if it performs some side effect. This is very useful for testing
purposes: tests can choose which services are active, so there are less chance
for unwanted side effects interfering with the code being tested.
2021-10-21 16:46:30 +07:00
Defining a service
==================
2021-10-18 15:48:07 +07:00
A service needs to implement the following interface:
2021-10-21 16:46:30 +07:00
.. js:data :: dependencies
2022-11-18 17:10:48 +07:00
2021-10-21 16:46:30 +07:00
Optional list of strings. It is the list of all dependencies (other services)
that this service needs
2021-10-18 15:48:07 +07:00
2021-10-21 16:46:30 +07:00
.. js:function :: start(env, deps)
2021-10-18 15:48:07 +07:00
2021-11-08 20:33:24 +07:00
:param Environment env: the application environment
2021-10-21 16:46:30 +07:00
:param Object deps: all requested dependencies
:returns: value of service or Promise<value of service>
2022-11-18 17:10:48 +07:00
2021-10-18 15:48:07 +07:00
This is the main definition for the service. It can return either a value or
a promise. In that case, the service loader simply waits for the promise to
resolve to a value, which is then the value of the service.
Some services do not export any value. They may just do their work without a
need to be directly called by other code. In that case, their value will be
set to `` null `` in `` env.services `` .
2021-10-21 16:46:30 +07:00
.. js:data :: async
2022-11-18 17:10:48 +07:00
2021-10-21 16:46:30 +07:00
Optional value. If given, it should be `true` or a list of strings.
2021-10-18 15:48:07 +07:00
Some services need to provide an asynchronous API. For example, the `rpc`
service is an asynchronous function, or the `orm` service provides a set of
functions to call the Odoo server.
In that case, it is possible for components that use a service to be
destroyed before the end of an asynchronous function call. Most of the time,
the asynchronous function call needs to be ignored. Doing otherwise is
potentially very risky, because the underlying component is no longer active.
The `async` flag is a way to do just that: it signals to the service creator
that all asynchronous calls coming from components should be left pending if
the component is destroyed.
Using a service
===============
A service that depends on other services and has properly declared its
`` dependencies `` simply receives a reference to the corresponding services
in the second argument of the `` start `` method.
The `` useService `` hook is the proper way to use a service in a component. It
simply returns a reference to the service value, that can then be used by the
component later. For example:
.. code-block :: javascript
import { useService } from "@web/core/utils/hooks";
class MyComponent extends Component {
setup() {
const rpc = useService("rpc");
onWillStart(async () => {
this.someValue = await rpc(...);
});
}
}
2021-10-21 16:46:30 +07:00
Reference List
==============
.. list-table ::
2021-11-01 14:49:44 +07:00
:widths: 25 75
2021-10-21 16:46:30 +07:00
:header-rows: 1
* - Technical Name
- Short Description
2021-11-04 03:08:35 +07:00
* - :ref: `cookie <frontend/services/cookie>`
2021-10-29 21:16:47 +07:00
- read or modify cookies
2021-11-04 03:08:35 +07:00
* - :ref: `effect <frontend/services/effect>`
2021-10-22 16:27:09 +07:00
- display graphical effects
2021-11-04 19:25:30 +07:00
* - :ref: `http <frontend/services/http>`
- perform low level http calls
2021-11-04 03:08:35 +07:00
* - :ref: `notification <frontend/services/notification>`
2021-11-03 03:07:34 +07:00
- display notifications
2021-11-04 05:00:44 +07:00
* - :ref: `router <frontend/services/router>`
- manage the browser url
2021-11-04 03:08:35 +07:00
* - :ref: `rpc <frontend/services/rpc>`
2021-10-21 16:46:30 +07:00
- send requests to the server
2021-11-15 18:27:45 +07:00
* - :ref: `scroller <frontend/services/scroller>`
- handle clicks on anchors elements
2021-11-04 03:08:35 +07:00
* - :ref: `title <frontend/services/title>`
2021-10-21 16:46:30 +07:00
- read or modify the window title
2021-11-04 03:08:35 +07:00
* - :ref: `user <frontend/services/user>`
2021-10-21 16:46:30 +07:00
- provides some information related to the current user
2021-11-04 03:08:35 +07:00
.. _frontend/services/cookie:
2021-10-29 21:16:47 +07:00
Cookie service
--------------
Overview
~~~~~~~~
- Technical name: `cookie`
- Dependencies: none
Provides a way to manipulate cookies. For example:
.. code-block :: javascript
cookieService.setCookie("hello", "odoo");
API
~~~
.. js:data :: current
Object representing each cookie and its value if any (or empty string)
.. js:function :: setCookie(name[, value, ttl])
:param string name: the name of the cookie that should be set
:param any value: optional. If given, the cookie will be set to that value
:param number ttl: optional. the time in seconds before the cookie will be deleted (default=1 year)
Sets the cookie `name` to the value `value` with a max age of `ttl`
2022-11-18 17:10:48 +07:00
2021-10-29 21:16:47 +07:00
.. js:function :: deleteCookie(name)
:param string name: name of the cookie
Deletes the cookie `name` .
2021-11-04 03:08:35 +07:00
.. _frontend/services/effect:
2021-10-22 16:27:09 +07:00
Effect service
--------------
Overview
~~~~~~~~
* Technical name: `effect`
* Dependencies: None
Effects are graphical elements that can be temporarily displayed on top of the page, usually to provide feedback to the user that something interesting happened.
A good example would be the rainbow man:
[MOV] content/*: move resource files into their related page's directory
Since odoo/documentation#903, the guideline for the location of new
resource (images, downloadable files, RST includes...) files is to place
those inside the directory of the RST page that references them.
For example, if `doc1.rst` has a reference to `image.png` and to
`download.zip`, the file structure should look like this:
├── parent_doc/
│ └── doc1/
│ │ └── image.png
│ │ └── download.zip
│ └── doc1.rst
│ └── doc2.rst
├── parent_doc.rst
Before this commit, most of the resource files were still located inside
'media' directories holding all the resource files referenced by RST
pages located at the same level as these directories. In the example
above, a single 'media' directory would hold all the resource files
referenced by both `doc1.rst` and `doc2.rst`. Doing so prevented us from
figuring out easily which resource file was referenced by which RST page
and, thus, lead to unused resource files piling up in the repository. It
also made it more complicated to define codeowners regex rules because a
team could not simply be assigned to `/some_page.*` but needed to be
assigned to both `/some_page\.rst` and to the location of 'media'.
In order to help new content writers figure out the guideline when
taking examples from other RST pages, this commit retroactively applies
the guideline to existing resource files and 'media' directories. The
left-over resource files that are not referenced by any RST page are
removed.
task-2497965
Part-of: odoo/documentation#2068
2022-05-20 16:54:32 +07:00
.. image :: services/rainbow_man.png
2021-10-22 16:27:09 +07:00
:alt: The rainbow man effect
:width: 600
:align: center
Here's how this can be displayed:
.. code-block :: javascript
const effectService = useService("effect");
effectService.add({
2021-11-18 20:04:54 +07:00
type: "rainbow_man", // can be omitted, default type is already "rainbow_man"
2021-10-22 16:27:09 +07:00
message: "Boom! Team record for the past 30 days.",
});
2022-11-18 17:10:48 +07:00
.. warning ::
2021-10-22 16:27:09 +07:00
The hook `useEffect` is not related to the effect service.
API
~~~
.. js:function :: effectService.add(options)
:param object options: the options for the effect. They will get passed along to the underlying effect component.
Display an effect.
The options are defined by:
.. code-block :: ts
2021-11-18 20:04:54 +07:00
interface EffectOptions {
// The name of the desired effect
type?: string;
[paramName: string]: any;
}
2021-10-22 16:27:09 +07:00
Available effects
~~~~~~~~~~~~~~~~~
Currently, the only effect is the rainbow man.
RainbowMan
***** *****
.. code-block :: javascript
effectService.add({ type: "rainbow_man" });
.. list-table ::
:widths: 20 40 40
:header-rows: 1
2021-11-18 20:04:54 +07:00
2022-11-18 17:10:48 +07:00
* - Name
2021-10-22 16:27:09 +07:00
- Type
- Description
2021-11-18 20:04:54 +07:00
* - `params.Component`
- `owl.Component?`
- Component class to instantiate inside the RainbowMan (will replace the message).
* - `params.props`
- `object?={}`
- If params.Component is given, its props can be passed with this argument.
2021-10-22 16:27:09 +07:00
* - `params.message`
2021-11-18 20:04:54 +07:00
- `string?="Well Done!"`
- Message is the notice the rainbowman holds.
If effects are disabled for the user, the rainbowman won't appear and a simple notification
will get displayed as a fallback.
If effects are enabled and params.Component is given, params.message is not used.
The message is a simple string or a string representing html
(prefer using params.Component if you want interactions in the DOM).
* - `params.messageIsHtml`
- `boolean?=false`
- Set to true if the message represents html, s.t. it will be correctly inserted into the DOM.
2021-10-22 16:27:09 +07:00
* - `params.img_url`
- `string?=/web/static/img/smile.svg`
- The url of the image to display inside the rainbow.
* - `params.fadeout`
- `("slow"|"medium"|"fast"|"no")?="medium"`
- Delay for rainbowman to disappear.
2021-11-18 20:04:54 +07:00
2021-10-22 16:27:09 +07:00
`"fast"` will make rainbowman dissapear quickly.
2022-11-18 17:10:48 +07:00
`"medium"` and `"slow"` will wait little longer before disappearing (can be used when `params.message` is longer).
2021-10-22 16:27:09 +07:00
`"no"` will keep rainbowman on screen until user clicks anywhere outside rainbowman.
How to add an effect
~~~~~~~~~~~~~~~~~~~~
2021-11-04 03:08:35 +07:00
.. _frontend/services/effect_registry:
2021-10-22 16:27:09 +07:00
The effects are stored in a registry called `effects` .
You can add new effects by providing a name and a function.
.. code-block :: javascript
const effectRegistry = registry.category("effects");
effectRegistry.add("rainbow_man", rainbowManEffectFunction);
The function must follow this API:
.. js:function :: <newEffectFunction> (env, params)
:param Env env: the environment received by the service
2021-11-18 20:04:54 +07:00
2021-10-22 16:27:09 +07:00
:param object params: the params received from the add function on the service.
:returns: `({Component, props} | void)` A component and its props or nothing.
2022-11-18 17:10:48 +07:00
This function must create a component and return it. This component is mounted inside the
2021-10-22 16:27:09 +07:00
effect component container.
Example
~~~~~~~
2022-11-18 17:10:48 +07:00
Let's say we want to add an effect that add a sepia look at the page.
2021-10-22 16:27:09 +07:00
.. code-block :: javascript
/** @odoo-module ** /
import { registry } from "@web/core/registry";
const { Component, tags } = owl;
class SepiaEffect extends Component {}
SepiaEffect.template = tags.xml`
<div style="
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
pointer-events: none;
background: rgba(124,87,0, 0.4);
"></div>
`;
export function sepiaEffectProvider(env, params = {}) {
return {
Component: SepiaEffect,
};
}
const effectRegistry = registry.category("effects");
effectRegistry.add("sepia", sepiaEffectProvider);
2022-11-18 17:10:48 +07:00
And then, call it somewhere you want and you will see the result.
2021-10-22 16:27:09 +07:00
Here, it is called in webclient.js to make it visible everywhere for the example.
.. code-block :: javascript
const effectService = useService("effect");
effectService.add({ type: "sepia" });
[MOV] content/*: move resource files into their related page's directory
Since odoo/documentation#903, the guideline for the location of new
resource (images, downloadable files, RST includes...) files is to place
those inside the directory of the RST page that references them.
For example, if `doc1.rst` has a reference to `image.png` and to
`download.zip`, the file structure should look like this:
├── parent_doc/
│ └── doc1/
│ │ └── image.png
│ │ └── download.zip
│ └── doc1.rst
│ └── doc2.rst
├── parent_doc.rst
Before this commit, most of the resource files were still located inside
'media' directories holding all the resource files referenced by RST
pages located at the same level as these directories. In the example
above, a single 'media' directory would hold all the resource files
referenced by both `doc1.rst` and `doc2.rst`. Doing so prevented us from
figuring out easily which resource file was referenced by which RST page
and, thus, lead to unused resource files piling up in the repository. It
also made it more complicated to define codeowners regex rules because a
team could not simply be assigned to `/some_page.*` but needed to be
assigned to both `/some_page\.rst` and to the location of 'media'.
In order to help new content writers figure out the guideline when
taking examples from other RST pages, this commit retroactively applies
the guideline to existing resource files and 'media' directories. The
left-over resource files that are not referenced by any RST page are
removed.
task-2497965
Part-of: odoo/documentation#2068
2022-05-20 16:54:32 +07:00
.. image :: services/odoo_sepia.png
2021-10-22 16:27:09 +07:00
:alt: Odoo in sepia
:width: 600
:align: center
2021-11-04 19:25:30 +07:00
.. _frontend/services/http:
Http Service
------------
Overview
~~~~~~~~
* Technical name: `http`
* Dependencies: None
While most interactions between the client and the server in odoo are `RPCs` (`XMLHTTPRequest` ), lower level
control on requests may sometimes be required.
This service provides a way to send `get` and `post` `http requests <https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods> `_ .
API
~~~
.. js:function :: async get(route[,readMethod = "json"])
:param string route: the url to send the request to
:param string readMethod: the response content type. Can be "text", "json", "formData", "blob", "arrayBuffer".
:returns: the result of the request with the format defined by the readMethod argument.
Sends a get request.
.. js:function :: async post(route [,params = {}, readMethod = "json"])
:param string route: the url to send the request to
:param object params: key value data to be set in the form data part of the request
:param string readMethod: the response content type. Can be "text", "json", "formData", "blob", "arrayBuffer".
:returns: the result of the request with the format defined by the readMethod argument.
Sends a post request.
Example
~~~~~~~
.. code-block :: javascript
const httpService = useService("http");
const data = await httpService.get("https://something.com/posts/1");
2022-11-18 17:10:48 +07:00
// ...
2021-11-04 19:25:30 +07:00
await httpService.post("https://something.com/posts/1", { title: "new title", content: "new content" });
2021-11-04 03:08:35 +07:00
.. _frontend/services/notification:
2021-11-03 03:07:34 +07:00
Notification service
--------------------
Overview
~~~~~~~~
* Technical name: `notification`
* Dependencies: None
The `notification` service allows to display notifications on the screen.
2022-11-18 17:10:48 +07:00
2021-11-03 03:07:34 +07:00
.. code-block :: javascript
const notificationService = useService("notification");
2022-11-18 17:10:48 +07:00
notificationService.add("I'm a very simple notification");
2021-11-03 03:07:34 +07:00
API
~~~
.. js:function :: add(message[, options])
2022-11-18 17:10:48 +07:00
2021-11-03 03:07:34 +07:00
:param string message: the notification message to display
:param object options: the options of the notification
:returns: a function to close the notification
Shows a notification.
The options are defined by:
.. list-table ::
:widths: 15 30 55
:header-rows: 1
* - Name
- Type
- Description
* - `title`
- string
- Add a title to the notification
* - `type`
- `warning` | `danger` | `success` | `info`
- Changes the background color according to the type
* - `sticky`
- boolean
- Whether or not the notification should stay until dismissed
* - `className`
- string
- additional css class that will be added to the notification
* - `onClose`
- function
- callback to be executed when the notification closes
* - `buttons`
- button[] (see below)
- list of button to display in the notification
The buttons are defined by:
.. list-table ::
:widths: 15 30 55
:header-rows: 1
* - Name
- Type
- Description
* - `name`
- string
- The button text
* - `onClick`
- function
- callback to execute when the button is clicked
* - `primary`
- boolean
- whether the button should be styled as a primary button
Examples
~~~~~~~~
A notification for when a sale deal is made with a button to go some kind of commission page.
.. code-block :: javascript
2022-11-18 17:10:48 +07:00
2021-11-03 03:07:34 +07:00
// in setup
this.notificationService = useService("notification");
2022-11-14 20:17:36 +07:00
this.actionService = useService("action");
2021-11-03 03:07:34 +07:00
// later
this.notificationService.add("You closed a deal!", {
title: "Congrats",
type: "success",
buttons: [
{
name: "See your Commission",
onClick: () => {
this.actionService.doAction("commission_action");
},
},
],
});
[MOV] content/*: move resource files into their related page's directory
Since odoo/documentation#903, the guideline for the location of new
resource (images, downloadable files, RST includes...) files is to place
those inside the directory of the RST page that references them.
For example, if `doc1.rst` has a reference to `image.png` and to
`download.zip`, the file structure should look like this:
├── parent_doc/
│ └── doc1/
│ │ └── image.png
│ │ └── download.zip
│ └── doc1.rst
│ └── doc2.rst
├── parent_doc.rst
Before this commit, most of the resource files were still located inside
'media' directories holding all the resource files referenced by RST
pages located at the same level as these directories. In the example
above, a single 'media' directory would hold all the resource files
referenced by both `doc1.rst` and `doc2.rst`. Doing so prevented us from
figuring out easily which resource file was referenced by which RST page
and, thus, lead to unused resource files piling up in the repository. It
also made it more complicated to define codeowners regex rules because a
team could not simply be assigned to `/some_page.*` but needed to be
assigned to both `/some_page\.rst` and to the location of 'media'.
In order to help new content writers figure out the guideline when
taking examples from other RST pages, this commit retroactively applies
the guideline to existing resource files and 'media' directories. The
left-over resource files that are not referenced by any RST page are
removed.
task-2497965
Part-of: odoo/documentation#2068
2022-05-20 16:54:32 +07:00
.. image :: services/notification_service.png
2021-11-03 03:07:34 +07:00
:width: 600 px
:alt: Example of notification
:align: center
A notification that closes after a second:
.. code-block :: javascript
const notificationService = useService("notification");
const close = notificationService.add("I will be quickly closed");
setTimeout(close, 1000);
2021-11-04 05:00:44 +07:00
.. _frontend/services/router:
Router Service
--------------
Overview
~~~~~~~~
- Technical name: `router`
- Dependencies: none
The `router` service provides three features:
* information about the current route
* a way for the application to update the url, depending on its state
* listens to every hash change, and notifies the rest of the application
API
~~~
.. js:data :: current
:noindex:
The current route can be accessed with the `` current `` key. It is an object
with the following information:
2022-11-18 17:10:48 +07:00
2021-11-04 05:00:44 +07:00
* `pathname (string)` : the path for the current location (most likely `/web` )
* `search (object)` : a dictionary mapping each search keyword (the querystring)
from the url to its value. An empty string is the value if no value was
explicitely given
2022-11-18 17:10:48 +07:00
* `hash (object)` : same as above, but for values described in the hash.
2021-11-04 05:00:44 +07:00
For example:
2022-11-18 17:10:48 +07:00
.. code-block :: javascript
2021-11-04 05:00:44 +07:00
// url = /web?debug=assets#action=123&owl&menu_id=174
const { pathname, search, hash } = env.services.router.current;
console.log(pathname); // /web
console.log(search); // { debug="assets" }
console.log(hash); // { action:123, owl: "", menu_id: 174 }
Updating the URL is done with the `pushState` method:
.. js:function :: pushState(hash: object[, replace?: boolean])
:param Object hash: object containing a mapping from some keys to some values
:param boolean replace: if true, the url will be replaced, otherwise only
key/value pairs from the `hash` will be updated.
Updates the URL with each key/value pair from the `hash` object. If a value is
set to an empty string, the key is added to the url without any corresponding
value.
If true, the `replace` argument tells the router that the url hash should be
completely replaced (so values not present in the `hash` object will be removed).
This method call does not reload the page. It also does not trigger a
`hashchange` event, nor a `ROUTE_CHANGE` in the :ref: `main bus <frontend/framework/bus>` .
This is because this method is intended to only updates the url. The code calling
this method has the responsibility to make sure that the screen is updated as
well.
For example:
.. code-block :: javascript
// url = /web#action_id=123
routerService.pushState({ menu_id: 321 });
// url is now /web#action_id=123&menu_id=321
routerService.pushState({ yipyip: "" }, replace: true);
// url is now /web#yipyip
Finally, the `redirect` method will redirect the browser to a specified url:
.. js:function :: redirect(url[, wait])
2022-11-18 17:10:48 +07:00
2021-11-04 05:00:44 +07:00
:param string url: a valid url
:param boolean wait: if true, wait for the server to be ready, and redirect after
2022-11-18 17:10:48 +07:00
2021-11-04 05:00:44 +07:00
Redirect the browser to `url` . This method reloads the page. The `wait`
argument is rarely used: it is useful in some cases where we know that the
server will be unavailable for a short duration, typically just after an addon
update or install operation.
.. note ::
The router service emits a `ROUTE_CHANGE` event on the :ref: `main bus <frontend/framework/bus>`
whenever the current route has changed.
2021-11-04 03:08:35 +07:00
.. _frontend/services/rpc:
2021-10-21 16:46:30 +07:00
RPC service
-----------
Overview
~~~~~~~~
- Technical name: `rpc`
- Dependencies: none
2021-10-18 15:48:07 +07:00
The `rpc` service provides a single asynchronous function to send requests to
2021-10-21 16:46:30 +07:00
the server. Calling a controller is very simple: the route should be the first
argument and optionally, a `` params `` object can be given as a second argument.
.. code-block :: javascript
2021-10-18 15:48:07 +07:00
2022-11-18 17:10:48 +07:00
// in setup
2021-10-21 16:46:30 +07:00
this.rpc = useService("rpc");
2021-10-18 15:48:07 +07:00
2021-10-21 16:46:30 +07:00
// somewhere else, in an async function:
const result = await this.rpc("/my/route", { some: "value" });
2021-10-18 15:48:07 +07:00
.. note ::
2022-11-18 17:10:48 +07:00
2021-10-18 15:48:07 +07:00
Note that the `` rpc `` service is considered a low-level service. It should
only be used to interact with Odoo controllers. To work with models (which
is by far the most important usecase), one should use the `` orm `` service
instead.
2021-10-21 16:46:30 +07:00
API
~~~
2021-10-18 15:48:07 +07:00
2021-10-21 16:46:30 +07:00
.. js:function :: rpc(route, params, settings)
2021-10-18 15:48:07 +07:00
2021-10-21 16:46:30 +07:00
:param string route: route targeted by the request
2023-04-25 15:57:23 +07:00
:param Object params: (optional) parameters sent to the server
:param Object settings: (optional) request settings (see below)
2022-11-18 17:10:48 +07:00
2021-10-21 16:46:30 +07:00
The `` settings `` object can contain:
2022-11-18 17:10:48 +07:00
2021-10-21 16:46:30 +07:00
- `` xhr `` , which should be a `` XMLHTTPRequest `` object. In that case,
the `` rpc `` method will simply use it instead of creating a new one. This
is useful when one accesses advanced features of the `XMLHTTPRequest` API.
- `` silent (boolean) `` If set to `` true `` , the web client will not provide
a feedback that there is a pending rpc.
2021-10-18 15:48:07 +07:00
The `` rpc `` service communicates with the server by using a `` XMLHTTPRequest ``
object, configured to work with the `` application/json `` content type. So clearly
the content of the request should be JSON serializable. Each request done by
this service uses the `` POST `` http method.
Server errors actually return the response with an http code 200. But the `` rpc ``
service will treat them as error.
Error Handling
2021-10-21 16:46:30 +07:00
~~~~~~~~~~~~~~
2021-10-18 15:48:07 +07:00
An rpc can fail for two main reasons:
* either the odoo server returns an error (so, we call this a `` server `` error).
In that case the http request will return with an http code 200 BUT with a
response object containing an `` error `` key.
* or there is some other kind of network error
When a rpc fails, then:
* the promise representing the rpc is rejected, so the calling code will crash,
unless it handles the situation
2023-02-13 22:50:13 +07:00
* an event `` RPC_ERROR `` is triggered on the main application bus. The event payload
2021-10-18 15:48:07 +07:00
contains a description of the cause of the error:
If it is a server error (the server code threw an exception). In that case
the event payload will be an object with the following keys:
* `` type = 'server' ``
* `` message(string) ``
2022-11-18 17:10:48 +07:00
*
2021-10-18 15:48:07 +07:00
`` code(number) ``
2022-11-18 17:10:48 +07:00
*
2021-10-18 15:48:07 +07:00
`` name(string) `` (optional, used by the error service to look for an appropriate
dialog to use when handling the error)
* `` subType(string) `` (optional, often used to determine the dialog title)
* `` data(object) `` (optional object that can contain various keys among which
`` debug `` : the main debug information, with the call stack)
If it is a network error, then the error description is simply an object
`` {type: 'network'} `` .
2021-11-04 03:08:35 +07:00
When a network error occurs, a :ref: `notification <frontend/services/notification>` is
2021-11-03 03:07:34 +07:00
displayed and the server is regularly contacted until it responds. The
notification is closed as soon as the server responds.
2021-10-21 16:46:30 +07:00
2021-11-15 18:27:45 +07:00
.. _frontend/services/scroller:
Scroller service
----------------
Overview
~~~~~~~~
- Technical name: `scroller`
- Dependencies: none
Whenever the user clicks on an anchor in the web client, this service automatically scrolls
to the target (if appropriate).
The service adds an event listener to get `click` 's on the document. The service checks
2022-11-18 17:10:48 +07:00
if the selector contained in its href attribute is valid to distinguish anchors and Odoo
2021-11-15 18:27:45 +07:00
actions (e.g. `<a href="#target_element"></a>` ). It does nothing if it is not the case.
2022-11-18 17:10:48 +07:00
An event `SCROLLER:ANCHOR_LINK_CLICKED` is triggered on the main application bus if the click seems to be
2021-11-15 18:27:45 +07:00
targeted at an element. The event contains a custom event containing the `element` matching and its `id` as a reference.
2022-11-18 17:10:48 +07:00
It may allow other parts to handle a behavior relative to anchors themselves. The original event is also
given as it might need to be prevented. If the event is not prevented, then the user interface will
2021-11-15 18:27:45 +07:00
scroll to the target element.
API
~~~
The following values are contained in the `anchor-link-clicked` custom event explained above.
.. list-table ::
:widths: 25 25 50
:header-rows: 1
2022-11-18 17:10:48 +07:00
* - Name
2021-11-15 18:27:45 +07:00
- Type
- Description
* - `element`
- `HTMLElement | null`
- The anchor element targeted by the href
* - `id`
- `string`
- The id contained in the href
* - `originalEv`
- `Event`
- The original click event
.. note ::
The scroller service emits a `SCROLLER:ANCHOR_LINK_CLICKED` event on the :ref: `main bus <frontend/framework/bus>` .
To avoid the default scroll behavior of the scroller service, you must use `preventDefault()` on the event given
to the listener so that you can implement your own behavior correctly from the listener.
2021-11-04 03:08:35 +07:00
.. _frontend/services/title:
2021-10-21 16:46:30 +07:00
Title Service
-------------
Overview
~~~~~~~~
- Technical name: `title`
- Dependencies: none
The `title` service offers a simple API that allows to read/modify the document
title. For example, if the current document title is "Odoo", we can change it
to "Odoo 15 - Apple" by using the following command:
.. code-block :: javascript
// in some component setup method
const titleService = useService("title");
titleService.setParts({ odoo: "Odoo 15", fruit: "Apple" });
API
~~~
The `` title `` service manipulates the following interface:
.. code-block :: ts
interface Parts {
[key: string]: string | null;
}
Each key represents the identity of a part of the title, and each value is the
string that is displayed, or `null` if it has been removed.
Its API is:
.. js:data :: current
2021-10-29 21:16:47 +07:00
:noindex:
2021-10-21 16:46:30 +07:00
This is a string representing the current title. It is structured in the
following way: `` value_1 - ... - value_n `` where each `value_i` is a (non null)
value found in the `Parts` object (returned by the `getParts` function)
2022-11-18 17:10:48 +07:00
2021-10-21 16:46:30 +07:00
.. js:function :: getParts
:returns: Parts the current `Parts` object maintained by the title service
.. js:function :: setParts(parts)
:param Parts parts: object representing the required change
The `` setParts `` method allows to add/replace/delete several parts of the title.
Delete a part (a value) is done by setting the associated key value to `null` .
Note that one can only modify a single part without affecting the other
parts. For example, if the title is composed of the following parts:
.. code-block :: javascript
{ odoo: "Odoo", action: "Import" }
with `` current `` value being `` Odoo - Import `` , then
.. code-block :: javascript
setParts({
action: null,
});
will change the title to `` Odoo `` .
2021-11-04 03:08:35 +07:00
.. _frontend/services/user:
2021-10-21 16:46:30 +07:00
User service
------------
2021-10-21 16:46:30 +07:00
Overview
2021-10-21 16:46:30 +07:00
~~~~~~~~
2021-10-21 16:46:30 +07:00
* Technical name: `user`
2022-11-18 17:10:48 +07:00
* Dependencies: `rpc`
2021-10-21 16:46:30 +07:00
2022-11-18 17:10:48 +07:00
The `user` service provides a bunch of data and a few helper functions concerning
2021-10-21 16:46:30 +07:00
the connected user.
API
2021-10-21 16:46:30 +07:00
~~~
2021-10-21 16:46:30 +07:00
.. list-table ::
:widths: 25 25 50
:header-rows: 1
2022-11-18 17:10:48 +07:00
* - Name
2021-10-21 16:46:30 +07:00
- Type
- Description
* - `` context ``
- `` Object ``
2021-11-04 03:08:35 +07:00
- The :ref: `user context<frontend/framework/user_context>`
2021-10-21 16:46:30 +07:00
* - `` db ``
- `` Object ``
- Info about the database
* - `` home_action_id ``
- `` (number | false) ``
- Id of the action used as home for the user
* - `` isAdmin ``
- `` boolean ``
- Whether the user is an admin (group `base.group_erp_manager` or superuser)
* - `` isSystem ``
- `` boolean ``
- Whether the user is part of the system group (`base.group_system` )
* - `` lang ``
- `` string ``
2022-11-18 17:10:48 +07:00
- language used
2021-10-21 16:46:30 +07:00
* - `` name ``
- `` string ``
- Name of the user
* - `` partnerId ``
- `` number ``
- Id of the partner instance of the user
* - `` tz ``
- `` string ``
- The timezone of the user
* - `` userId ``
- `` number ``
- Id of the user
* - `` userName ``
- `` string ``
- Alternative nick name of the user
.. js:function :: updateContext(update)
:param object update: the object to update the context with
2021-11-04 03:08:35 +07:00
update the :ref: `user context<frontend/framework/user_context>` with the given object.
2021-10-21 16:46:30 +07:00
.. code-block :: javascript
userService.updateContext({ isFriend: true })
.. js:function :: removeFromContext(key)
:param string key: the key of the targeted attribute
2021-11-04 03:08:35 +07:00
remove the value with the given key from the :ref: `user context<frontend/framework/user_context>`
2021-10-21 16:46:30 +07:00
2022-11-21 23:23:49 +07:00
.. code-block :: javascript
2021-10-21 16:46:30 +07:00
userService.removeFromContext("isFriend")
.. js:function :: hasGroup(group)
:param string group: the xml_id of the group to look for
:returns: `Promise<boolean>` is the user in the group
check if the user is part of a group
2022-11-21 23:23:49 +07:00
.. code-block :: javascript
2021-10-21 16:46:30 +07:00
const isInSalesGroup = await userService.hasGroup("sale.group_sales")