Skip to content

Commit 16e10c5

Browse files
committed
[IMP] developer: document how to create standalone owl apps
Since we've introduced Owl, developers want more and more to create standalone Owl applications outside of the webclient. This commit introduces a How-to for doing just that. task-3580007 closes #6553 X-original-commit: 1fc36ff Related: odoo/odoo#143073 Signed-off-by: Samuel Degueldre (sad) <[email protected]>
1 parent 4219829 commit 16e10c5

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed

content/developer/howtos.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ How-to guides
1212
howtos/javascript_field
1313
howtos/javascript_view
1414
howtos/javascript_client_action
15+
howtos/standalone_owl_application
1516
howtos/web_services
1617
howtos/company
1718
howtos/create_reports
@@ -42,6 +43,12 @@ How-to guides
4243

4344
Learn how to create client actions in the Odoo JavaScript web framework.
4445

46+
.. card:: Create a standalone Owl application
47+
:target: howtos/standalone_owl_application
48+
49+
Learn how to create a public-facing Owl application outside of the web client using a
50+
controller and the Odoo JavaScript framework.
51+
4552
.. card:: Web services
4653
:target: howtos/web_services
4754

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
===================================
2+
Create a standalone Owl application
3+
===================================
4+
5+
For any number of reasons, you may want to have a standalone Owl application that isn't a part of
6+
the web client. One example in Odoo is the self-ordering application, that lets customers order
7+
food from their phone. In this chapter we will go into what's required to achieve something like this.
8+
9+
Overview
10+
========
11+
12+
To have a standalone Owl app, a few things are required:
13+
14+
- a root component for the application
15+
- some setup code to start the services and mount the component
16+
- an assets bundle that contains the setup code
17+
- a QWeb view that calls the assets bundle
18+
- a controller that renders the view
19+
20+
1. Root component
21+
=================
22+
23+
To keep things simple, let's start with a very straightforward component that just renders
24+
"Hello, World!". This will let us know at a glance if our setup is working.
25+
26+
First, create the template in :file:`/your_module/static/src/standalone_app/root.xml`.
27+
28+
.. code-block:: xml
29+
30+
<?xml version="1.0" encoding="UTF-8"?>
31+
<templates xml:space="preserve">
32+
<t t-name="your_module.Root">
33+
Hello, World!
34+
</t>
35+
</templates>
36+
37+
Then create the JavaScript file for that component in :file:`/your_module/static/src/standalone_app/root.js`.
38+
39+
.. code-block:: js
40+
41+
/** @odoo-module */
42+
import { Component } from "@odoo/owl";
43+
44+
export class Root extends Component {
45+
static template = "your_module.Root";
46+
static props = {};
47+
}
48+
49+
.. seealso::
50+
:ref:`Owl components reference<frontend/components>`.
51+
52+
2. Setting up the environment and mounting the application
53+
==========================================================
54+
55+
An Owl application needs an environment, and the Odoo JavaScript framework needs that environment to
56+
contain the :ref:`services<frontend/services>`.
57+
Starting the services is also required to load the translations, which we need to do before mounting
58+
our Owl application, so that we can give Owl a working translation function.
59+
60+
Create the JavaScript file that will mount the app in :file:`/your_module/static/src/standalone_app/app.js`.
61+
62+
.. code-block:: js
63+
64+
/** @odoo-module */
65+
import { whenReady } from "@odoo/owl";
66+
import { mountComponent } from "@web/env";
67+
import { Root } from "./root";
68+
69+
whenReady(() => mountComponent(Root, document.body));
70+
71+
72+
3. Creating an assets bundle containing our code
73+
================================================
74+
75+
In the manifest of your module, create a new :ref:`assets bundle<reference/assets_bundle>`.
76+
It should include the `web._assets_core` bundle, which contains the Odoo JavaScript
77+
framework and the core libraries it needs (e.g. Owl and luxon), after which you can have a
78+
glob that adds all the files for your application in the bundle.
79+
80+
.. code-block:: py
81+
:emphasize-lines: 9-10
82+
83+
{
84+
# ...
85+
'assets': {
86+
'your_module.assets_standalone_app': [
87+
('include', 'web._assets_helpers'),
88+
'web/static/src/scss/pre_variables.scss',
89+
'web/static/lib/bootstrap/scss/_variables.scss',
90+
('include', 'web._assets_bootstrap'),
91+
('include', 'web._assets_core'),
92+
'your_module/static/src/standalone_app/**/*',
93+
],
94+
}
95+
}
96+
97+
The other lines are bundles and scss files that are required to make Bootstrap work. They are
98+
mandatory, as the components of the web framework use bootstrap classes for their styling and
99+
layout.
100+
101+
.. caution::
102+
Make sure that the files for your standalone app are only added to this bundle, if you already
103+
have a definition for `web.assets_backend` or `web.assets_frontend` and they have globs, make
104+
sure these globs don't match the files for your standalone app, otherwise the startup code for
105+
your app will conflict with the existing startup code in those bundles.
106+
107+
.. seealso::
108+
:ref:`Module manifest reference<reference/module/manifest>`.
109+
110+
4. XML view that calls the assets bundle
111+
========================================
112+
113+
Now that we have created our assets bundle, we need to create a
114+
:ref:`QWeb view<reference/view_architecture/qweb>` that uses that assets bundle.
115+
116+
.. code-block:: xml
117+
118+
<?xml version="1.0" encoding="utf-8"?>
119+
<odoo>
120+
<template id="your_module.standalone_app">&lt;!DOCTYPE html&gt;
121+
<html>
122+
<head>
123+
<script type="text/javascript">
124+
var odoo = {
125+
csrf_token: "<t t-nocache="The csrf token must always be up to date." t-esc="request.csrf_token(None)"/>",
126+
debug: "<t t-out="debug"/>",
127+
__session_info__: <t t-esc="json.dumps(session_info)"/>,
128+
};
129+
</script>
130+
<t t-call-assets="your_module.assets_standalone_app" />
131+
</head>
132+
<body/>
133+
</html>
134+
</template>
135+
</odoo>
136+
137+
This template only does two things: it initializes the `odoo` global variable, then calls the assets
138+
bundle we just defined. Initializing the `odoo` global variable is a necessary step. This variable
139+
should be an object that contains the following:
140+
141+
- The CSRF token, which is required to interact with HTTP controllers in many cases.
142+
- The debug value, which is used in many places to add additional logging or developer-friendly checks.
143+
- `__session_info__`, that contains information from the server that is always needed and for which
144+
we don't want to perform an additional request. More on this in the next section.
145+
146+
5. Controller that renders the view
147+
===================================
148+
149+
Now that we have the view, we need to make it accessible to the user. For that purpose, we will create
150+
an :ref:`HTTP controller<reference/controllers>` that renders that view and returns it to the user.
151+
152+
.. code-block:: py
153+
154+
from odoo.http import request, route, Controller
155+
156+
class YourController(Controller):
157+
@route("/your_module/standalone_app", auth="public")
158+
def standalone_app(self):
159+
return request.render(
160+
'your_module.standalone_app',
161+
{
162+
'session_info': request.env['ir.http'].get_frontend_session_info(),
163+
}
164+
)
165+
166+
Notice how we're giving the template `session_info`. We get it from the `get_frontend_session_info`
167+
method, and it will end up containing information used by the web framework, such as the current
168+
user's ID if they are logged in, the server version, the Odoo edition, etc.
169+
170+
At this point, if you open the url `/your_module/standalone_app` in your brower, you should
171+
see a blank page with the text "Hello, World!". At this point, you can start actually writing the
172+
code for your app.

0 commit comments

Comments
 (0)