[ADD] developer: add javascript framework overview
closes odoo/documentation#1181 Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
This commit is contained in:
parent
7b1b1c795d
commit
ff5a50856f
@ -7,6 +7,7 @@ Javascript Modules
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
javascript/framework_overview
|
||||
javascript/javascript_cheatsheet
|
||||
javascript/javascript_reference
|
||||
javascript/mobile
|
||||
|
193
content/developer/reference/javascript/framework_overview.rst
Normal file
193
content/developer/reference/javascript/framework_overview.rst
Normal file
@ -0,0 +1,193 @@
|
||||
==================
|
||||
Framework Overview
|
||||
==================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The Odoo Javascript framework is a set of features/building blocks provided by
|
||||
the ``web/`` addon to help build odoo applications running in the browser. At
|
||||
the same time, the Odoo Javascript framework is a single page application,
|
||||
usually known as the *web client* (available at the url ``/web``).
|
||||
|
||||
The web client started as an application made with a custom class and widget
|
||||
system, but it is now transitioning to using native javascript classes instead,
|
||||
and Owl as a component system. This explains why both systems are currently in
|
||||
use in the codebase.
|
||||
|
||||
From a high-level perspective, the web client is a single-page application: it
|
||||
does not need to request a full page from the server each time the user performs
|
||||
an action. Instead, it only requests what it needs and then replaces/updates the
|
||||
current screen accordingly. Also, it manages the url to keep it in sync with
|
||||
the current state.
|
||||
|
||||
The javascript framework (all or some parts) is also used in other situations,
|
||||
such as the Odoo website or the point of sale. This reference is mostly focused
|
||||
on the web client.
|
||||
|
||||
.. note::
|
||||
|
||||
It is common in the Odoo ecosystem to see the words *frontend* and *backend*
|
||||
as synonyms for the odoo website (public) and the web client, respectively.
|
||||
This terminology is not to be confused with the more common use of
|
||||
browser-code (frontend) and server (backend).
|
||||
|
||||
.. note::
|
||||
|
||||
In this documentation, the word *component* always refers to new Owl
|
||||
components, and *widget* refers to old Odoo widgets.
|
||||
|
||||
.. note::
|
||||
|
||||
All new development should be done in Owl, if possible!
|
||||
|
||||
Code structure
|
||||
==============
|
||||
|
||||
The ``web/static/src`` folder contains all the ``web/`` javascript (and css and
|
||||
templates) codebase. Here is a list of the most important folders:
|
||||
|
||||
- ``core/`` most of the low level features
|
||||
- ``fields/`` all field components
|
||||
- ``views/`` all javascript views components (``form``, ``list``, ...)
|
||||
- ``search/`` control panel, search bar, search panel, ...
|
||||
- ``webclient/`` the web client specific code: navbar, user menu, action service, ...
|
||||
|
||||
The ``web/static/src`` is the root folder. Everything inside can simply be
|
||||
imported by using the ``@web`` prefix. For example, here is how one can import
|
||||
the ``memoize`` function located in ``web/static/src/core/utils/functions``:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
import { memoize } from "@web/core/utils/functions";
|
||||
|
||||
WebClient Architecture
|
||||
======================
|
||||
|
||||
As mentioned above, the web client is an owl application. Here is a slightly
|
||||
simplified version of its template:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<t t-name="web.WebClient" owl="1">
|
||||
<body class="o_web_client">
|
||||
<NavBar/>
|
||||
<ActionContainer/>
|
||||
<MainComponentsContainer/>
|
||||
</body>
|
||||
</t>
|
||||
|
||||
As we can see, it basically is a wrapper for a navbar, the current action and
|
||||
some additional components. The ``ActionContainer`` is a higher order component
|
||||
that will display the current action controller (so, a client action, or a
|
||||
specific view in the case of actions of type ``act_window``). Managing actions
|
||||
is a huge part of its work: the action service keeps in memory a stack of
|
||||
all active actions (represented in the breadcrumbs), and coordinates each
|
||||
change.
|
||||
|
||||
Another interesting thing to note is the ``MainComponentsContainer``: it is
|
||||
simply a component that displays all components registered in the
|
||||
``main_components`` registry. This is how other parts of the system can extend
|
||||
the web client.
|
||||
|
||||
Building Blocks
|
||||
===============
|
||||
|
||||
Most of the web client is built with a few types of abstractions: registries,
|
||||
services, components and hooks.
|
||||
|
||||
Registries
|
||||
----------
|
||||
|
||||
Registries are basically a simple key/value mapping that stores some specific
|
||||
kind of objects. They are an important part of the extensibility of the UI:
|
||||
once some object is registered, the rest of the web client can use it. For
|
||||
example, the field registry contains all field components (or widgets) that
|
||||
can be used in views.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
import { registry } from "./core/registry";
|
||||
|
||||
class MyFieldChar extends owl.Component {
|
||||
// some code
|
||||
}
|
||||
|
||||
registry.category("fields").add("my_field_char", MyFieldChar);
|
||||
|
||||
Note that we import the main registry from ``@web/core/registry`` then open the
|
||||
sub registry ``fields``.
|
||||
|
||||
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
|
||||
(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 second:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
import { registry } from "./core/registry";
|
||||
|
||||
const myService = {
|
||||
dependencies: ["notification"],
|
||||
start(env, { notification }) {
|
||||
let counter = 1;
|
||||
setInterval(() => {
|
||||
notification.add(`Tick Tock ${counter++}`);
|
||||
}, 5000);
|
||||
}
|
||||
};
|
||||
|
||||
serviceRegistry.add("myService", myService);
|
||||
|
||||
Components and Hooks
|
||||
--------------------
|
||||
|
||||
Components and hooks are ideas coming from the
|
||||
`Owl component system <https://github.com/odoo/owl/blob/master/doc/readme.md>`_.
|
||||
Odoo components are simply owl components that are part of the web client.
|
||||
|
||||
`Hooks <https://github.com/odoo/owl/blob/master/doc/reference/hooks.md>`_ are a
|
||||
way to factorize code, even if it depends on lifecycle. This is a
|
||||
composable/functional way to inject a feature in a component. They can be seen
|
||||
as a kind of mixin.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
function useCurrentTime() {
|
||||
const state = useState({ now: new Date() });
|
||||
const update = () => state.now = new Date();
|
||||
let timer;
|
||||
onWillStart(() => timer = setInterval(update, 1000));
|
||||
onWillUnmount(() => clearInterval(timer));
|
||||
return state;
|
||||
}
|
||||
|
||||
Browser Object
|
||||
==============
|
||||
|
||||
The javascript framework also provides a special object ``browser`` that
|
||||
provides access to all browser APIs, like ``location``, ``localStorage``
|
||||
or ``setTimeout``. For example, here is how one could use the
|
||||
``browser.setTimeout`` function:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
import { browser } from "@web/core/browser/browser";
|
||||
|
||||
// somewhere in code
|
||||
browser.setTimeout(someFunction, 1000);
|
||||
|
||||
It is mostly interesting for testing purposes: all code using the browser object
|
||||
can be tested easily by mocking the relevant functions for the duration of the
|
||||
test.
|
||||
|
||||
.. seealso::
|
||||
- `Owl Repository <https://github.com/odoo/owl>`_
|
Loading…
Reference in New Issue
Block a user