@odoo/owl 2.2.10 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/owl-devtools.zip +0 -0
- package/dist/owl.cjs.js +41 -26
- package/dist/owl.es.js +41 -27
- package/dist/owl.iife.js +41 -26
- package/dist/owl.iife.min.js +1 -1
- package/dist/types/compiler/code_generator.d.ts +1 -1
- package/dist/types/owl.d.ts +9 -1
- package/dist/types/runtime/index.d.ts +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
- package/CHANGELOG.md +0 -766
package/CHANGELOG.md
DELETED
|
@@ -1,766 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
This document contains an overview of all changes between Owl 1.x and
|
|
4
|
-
Owl 2.x, with some pointers on how to update the code.
|
|
5
|
-
|
|
6
|
-
Note that some of these changes can be magically implemented (for example, by
|
|
7
|
-
patching the `setup` method of `Component` to auto register all the lifecycle
|
|
8
|
-
methods as hooks). This will be done for the transition period, but will be
|
|
9
|
-
removed after.
|
|
10
|
-
|
|
11
|
-
## From Owl 1.x to Owl 2.0
|
|
12
|
-
|
|
13
|
-
All changes are documented here in no particular order.
|
|
14
|
-
|
|
15
|
-
**Components**
|
|
16
|
-
|
|
17
|
-
- components can now have empty content or multiple root nodes (htmlelement or text) ([details](#31-components-can-now-have-arbitrary-content))
|
|
18
|
-
- breaking: component.el is removed ([details](#9-componentel-is-removed))
|
|
19
|
-
- new `useEffect` hook ([doc](doc/reference/hooks.md#useeffect))
|
|
20
|
-
- new `onWillDestroy`, `onWillRender` and `onRendered` hooks ([doc](doc/reference/component.md#lifecycle))
|
|
21
|
-
- breaking: lifecycle methods are removed ([details](#1-component-lifecycle-methods-are-removed))
|
|
22
|
-
- breaking: can no longer be mounted on detached DOM ([details](#2-components-can-no-longer-be-mounted-in-a-detached-dom-element))
|
|
23
|
-
- breaking: standalone `mount` method API is simpler ([details](#4-mount-method-api-is-simpler))
|
|
24
|
-
- breaking: components can no longer be instantiated and mounted by hand ([details](#5-components-can-no-longer-be-instantiated-and-mounted-by-hand))
|
|
25
|
-
- breaking: components can no longer be unmounted/remounted ([details](#6-components-can-no-longer-be-unmountedremounted))
|
|
26
|
-
- breaking: template name is no longer inferred from the class name ([details](#7-template-name-is-no-longer-inferred-from-the-class-name))
|
|
27
|
-
- breaking: components no longer have a `shouldUpdate` method ([details](#8-components-no-longer-have-a-shouldupdate-method))
|
|
28
|
-
- breaking: components can no longer be mounted with position=self ([details](#11-components-can-no-longer-be-mounted-with-positionself))
|
|
29
|
-
- breaking: `render` method does not return a promise anymore ([details](#35-render-method-does-not-return-a-promise-anymore))
|
|
30
|
-
- breaking: `catchError` method is replaced by `onError` hook ([details](#36-catcherror-method-is-replaced-by-onerror-hook))
|
|
31
|
-
- breaking: Support for inline css (`css` tag and static `style`) has been removed ([details](#37-support-for-inline-css-css-tag-and-static-style-has-been-removed))
|
|
32
|
-
- new: prop validation system can now describe that additional props are allowed (with `*`) ([doc](doc/reference/props.md#props-validation))
|
|
33
|
-
- breaking: prop validation system does not allow default prop on a mandatory (not optional) prop ([doc](doc/reference/props.md#props-validation))
|
|
34
|
-
- breaking: rendering a component does not necessarily render child components ([details](#40-rendering-a-component-does-not-necessarily-render-child-components))
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
**Templates**
|
|
39
|
-
|
|
40
|
-
- breaking: `t-foreach` should always have a corresponding `t-key` ([details](#20-t-foreach-should-always-have-a-corresponding-t-key))
|
|
41
|
-
- breaking: `t-ref` does not work on components ([details](#29-t-ref-does-not-work-on-component))
|
|
42
|
-
- breaking: `t-raw` directive has been removed (replaced by `t-out`) ([details](#38-t-raw-directive-has-been-removed-replaced-by-t-out))
|
|
43
|
-
- new: add support for synthetic events ([doc](doc/reference/event_handling.md#synthetic-events))
|
|
44
|
-
- breaking: style/class on components are now regular props ([details](#10-styleclass-on-components-are-now-regular-props))
|
|
45
|
-
- new: components can use the `.bind` suffix to bind function props ([doc](doc/reference/props.md#binding-function-props))
|
|
46
|
-
- breaking: `t-on` does not accept expressions, only functions ([details](#30-t-on-does-not-accept-expressions-only-functions))
|
|
47
|
-
- new: an error is thrown if an handler defined in a `t-on-` directive is not a function (failed silently previously in some cases)
|
|
48
|
-
- breaking: `t-component` no longer accepts strings ([details](#17-t-component-no-longer-accepts-strings))
|
|
49
|
-
- new: the `this` variable in template expressions is now bound to the component
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
**Reactivity**
|
|
53
|
-
|
|
54
|
-
- finer grained reactivity: owl 2 tracks change per key/component
|
|
55
|
-
- finer grained reactivity: sub components can reobserve state ([doc](doc/reference/reactivity.md))
|
|
56
|
-
- new: `reactive` function: create reactive state (without being linked to a component) ([doc](doc/reference/reactivity.md#reactive))
|
|
57
|
-
- new: `markRaw` function: mark an object or array so that it is ignored by the reactivity system ([doc](doc/reference/reactivity.md#markraw))
|
|
58
|
-
- new: `toRaw` function: given a reactive objet, return the raw (non reactive) underlying object ([doc](doc/reference/reactivity.md#toraw))
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
**Slots**
|
|
62
|
-
|
|
63
|
-
- breaking: `t-set` does not define a slot any more ([details](#3-t-set-will-no-longer-work-to-define-a-slot))
|
|
64
|
-
- slots capabilities have been improved ([doc](doc/reference/slots.md))
|
|
65
|
-
- params can be give to slot content (to pass information from slot owner to slot user)
|
|
66
|
-
- slots are given as a `prop` (and can be manipulated/propagated to sub components )
|
|
67
|
-
- slots can define scopes (to pass information from slot user to slot owner)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
**Portal**
|
|
71
|
-
|
|
72
|
-
- Portal are now defined with `t-portal` ([details](#33-portal-are-now-defined-with-t-portal))
|
|
73
|
-
- portals can now have arbitrary content (no longer restricted to one single child)
|
|
74
|
-
- breaking: does no longer transfer dom events ([details](#13-portal-does-no-longer-transfer-dom-events))
|
|
75
|
-
- breaking: does render as an empty text node instead of `<portal/>` ([details](#14-portal-does-render-as-an-empty-text-node-instead-of-portal))
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
**Miscellaneous**
|
|
79
|
-
|
|
80
|
-
- improved performance
|
|
81
|
-
- much simpler code
|
|
82
|
-
- new App class to encapsulate a root Owl component (with the config for that application) ([doc](doc/reference/app.md))
|
|
83
|
-
- new `useEffect` hook ([doc](doc/reference/hooks.md#useeffect))
|
|
84
|
-
- breaking: `Context` is removed ([details](#15-context-is-removed))
|
|
85
|
-
- breaking: `env` is now totally empty ([details](#16-env-is-now-totally-empty))
|
|
86
|
-
- breaking: `env` is now frozen ([details](#28-env-is-now-frozen))
|
|
87
|
-
- new hook: `useChildSubEnv` (only applies to child components) ([details](#27-usechildsubenv-only-applies-to-child-components))
|
|
88
|
-
- breaking: most exports are exported at top level ([details](#18-most-exports-are-exported-at-top-level))
|
|
89
|
-
- breaking: properties are no longer set as attributes ([details](#19-properties-are-no-longer-set-as-attributes))
|
|
90
|
-
- breaking: `EventBus` api changed: it is now an `EventTarget` ([details](#21-eventbus-api-changed-it-is-now-an-eventtarget))
|
|
91
|
-
- breaking: `Store` is removed ([details](#22-store-is-removed))
|
|
92
|
-
- breaking: `Router` is removed ([details](#23-router-is-removed))
|
|
93
|
-
- breaking: transition system is removed ([details](#24-transition-system-is-removed))
|
|
94
|
-
- breaking: no more global components or templates ([details](#25-no-more-global-components-or-templates))
|
|
95
|
-
- breaking: `AsyncRoot` utility component is removed ([details](#26-asyncroot-utility-component-is-removed))
|
|
96
|
-
- breaking: `renderToString` function on qweb has been removed ([details](#32-rendertostring-on-qweb-has-been-removed))
|
|
97
|
-
- breaking: `debounce` utility function has been removed ([details](#34-debounce-utility-function-has-been-removed))
|
|
98
|
-
- breaking: `browser` object has been removed ([details](#39-browser-object-has-been-removed))
|
|
99
|
-
|
|
100
|
-
## Details/Rationale/Migration
|
|
101
|
-
|
|
102
|
-
All changes are listed in no particular order.
|
|
103
|
-
|
|
104
|
-
### 1. component lifecycle methods are removed
|
|
105
|
-
|
|
106
|
-
There was two ways to define hooks: the component methods (`willStart`, `mounted`, ...) and the hooks (`onWillStart`, `onMounted`, ...). In Owl 2, the component methods have been removed.
|
|
107
|
-
|
|
108
|
-
Rationale: it makes the implementation simpler and slightly faster. Hooks are more composable
|
|
109
|
-
than component methods. It enforces a single entry point to check all the useful lifecycle
|
|
110
|
-
calls (instead of it being scattered in the component definition). It feels more "modern".
|
|
111
|
-
|
|
112
|
-
Migration: lifecycle methods should be defined in the `setup`:
|
|
113
|
-
|
|
114
|
-
```js
|
|
115
|
-
class MyComponent extends Component {
|
|
116
|
-
mounted() {
|
|
117
|
-
// do something
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
should become:
|
|
122
|
-
```js
|
|
123
|
-
class MyComponent extends Component {
|
|
124
|
-
setup() {
|
|
125
|
-
onMounted(() => {
|
|
126
|
-
// do something
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Documentation: [Component Lifecycle](doc/reference/component.md#lifecycle)
|
|
133
|
-
|
|
134
|
-
### 2. components can no longer be mounted in a detached dom element
|
|
135
|
-
|
|
136
|
-
Nor document fragment.
|
|
137
|
-
|
|
138
|
-
Rationale: it is actually very difficult to do it: this implies that a component
|
|
139
|
-
can be mounted more than once, that we need to check every time different status,
|
|
140
|
-
that some elements is in the dom, and was a cause for bugs. Also, we don't use it
|
|
141
|
-
in practice. Removing this means that we have a much simpler mental model of what
|
|
142
|
-
happens.
|
|
143
|
-
|
|
144
|
-
Migration: well, not really easy. The code needs to be refactored in a different way.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
### 3. **`t-set` will no longer work to define a slot**
|
|
148
|
-
|
|
149
|
-
The `t-set` directive cannot define a slot anymore. Only the `t-set-slot` directive
|
|
150
|
-
can do it.
|
|
151
|
-
|
|
152
|
-
Rationale: it was left for compatibility reason, but was deprecated anyway.
|
|
153
|
-
|
|
154
|
-
Migration: `t-set` should be changed to `t-set-slot` (when defining a slot)
|
|
155
|
-
|
|
156
|
-
Example:
|
|
157
|
-
|
|
158
|
-
```xml
|
|
159
|
-
<SideBar><t t-set="content">content</t></SideBar>
|
|
160
|
-
```
|
|
161
|
-
should become:
|
|
162
|
-
```xml
|
|
163
|
-
<SideBar><t t-set-slot="content">content</t></SideBar>
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### 4. `mount` method API is simpler
|
|
167
|
-
|
|
168
|
-
Before, the `mount` method was used like this:
|
|
169
|
-
|
|
170
|
-
```js
|
|
171
|
-
await mount(Root, { target: document.body });
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
It is now simpler and takes the root component and a target argument:
|
|
175
|
-
|
|
176
|
-
```js
|
|
177
|
-
await mount(Root, document.body);
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
Rationale: the `mount` method is only useful anyway for small toy examples,
|
|
181
|
-
because real applications will need to configure the templates, the translations,
|
|
182
|
-
and other stuff. All complex usecases need to go through the new `App` class,
|
|
183
|
-
that encapsulates the root of an owl application.
|
|
184
|
-
|
|
185
|
-
Documentation: [Mounting a component](doc/reference/app.md#mount-helper)
|
|
186
|
-
|
|
187
|
-
### 5. components can no longer be instantiated and mounted by hand
|
|
188
|
-
|
|
189
|
-
In Owl 1, it was possible to instantiate a component by hand:
|
|
190
|
-
|
|
191
|
-
```js
|
|
192
|
-
const root = new Root();
|
|
193
|
-
await root.mount(document.body);
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
Now, it is no longer possible. All component instantiations should be done by
|
|
197
|
-
the owl framework itself.
|
|
198
|
-
|
|
199
|
-
Rationale: the `mount` method does not make sense for all non root components.
|
|
200
|
-
Also, the fact that it was possible for a component to be sometimes root,
|
|
201
|
-
sometimes a child made for a weird constructor signature. This changes makes it
|
|
202
|
-
simpler.
|
|
203
|
-
|
|
204
|
-
Migration: all code doing that should use either the `mount` method (if the use
|
|
205
|
-
case is simple enough, or the `App` class):
|
|
206
|
-
|
|
207
|
-
```js
|
|
208
|
-
const app = new App(Root);
|
|
209
|
-
app.configure({ templates: ..., ...});
|
|
210
|
-
await app.mount(document.body);
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### 6. components can no longer be unmounted/remounted
|
|
214
|
-
|
|
215
|
-
Rationale: this is a very difficult feature to implement (it adds a lot of possible
|
|
216
|
-
state transitions), compared to its benefit.
|
|
217
|
-
|
|
218
|
-
Migration: all code using it should find a way to export and reimport the state
|
|
219
|
-
|
|
220
|
-
### 7. template name is no longer inferred from the class name
|
|
221
|
-
|
|
222
|
-
Before, it was possible to define a component without specifying its template:
|
|
223
|
-
|
|
224
|
-
```js
|
|
225
|
-
class Blabla extends Component {
|
|
226
|
-
// no static template here!
|
|
227
|
-
}
|
|
228
|
-
```
|
|
229
|
-
with the `Blabla` template. It also worked with subclasses. But then, this means
|
|
230
|
-
that the code had to look up all the super classes names to find the correct
|
|
231
|
-
template.
|
|
232
|
-
|
|
233
|
-
Rationale: in practice, it is not really useful, since all templates are usually
|
|
234
|
-
namespaced: `web.SomeComponent` anyway. All the trouble to do that was just not
|
|
235
|
-
worth it.
|
|
236
|
-
|
|
237
|
-
Migration: simply explicitely defines the template key everytime:
|
|
238
|
-
|
|
239
|
-
```js
|
|
240
|
-
class Blabla extends Component {}
|
|
241
|
-
Blabla.template = "Blabla";
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### 8. components no longer have a `shouldUpdate` method
|
|
245
|
-
|
|
246
|
-
Rationale: `shouldUpdate` is a dangerous method to use, that may cause a lot of
|
|
247
|
-
issues. Vue does not have such a mechanism (see https://github.com/vuejs/vue/issues/4255),
|
|
248
|
-
because the reactivity system in Vue is smart enough to only rerender the minimal
|
|
249
|
-
subset of components that is subscribed to a piece of state. Now, Owl 2 features
|
|
250
|
-
a much more powerful reactivity system, so the same rationale applies: in a way,
|
|
251
|
-
it's like each Owl 2 component has a `shouldUpdate` method that precisely tracks
|
|
252
|
-
every value used by the component.
|
|
253
|
-
|
|
254
|
-
Migration code: remove the `shouldUpdate` methods, and it should work as well
|
|
255
|
-
as before.
|
|
256
|
-
|
|
257
|
-
### 9. component.el is removed
|
|
258
|
-
|
|
259
|
-
This comes from the fact that Owl 2 supports fragments (arbitrary content).
|
|
260
|
-
|
|
261
|
-
Migration: if one need a reference to the root htmlelement of a template, it is
|
|
262
|
-
suggested to simply add a `ref` on it, and access the reference as needed.
|
|
263
|
-
|
|
264
|
-
Documentation: [Refs](doc/reference/refs.md)
|
|
265
|
-
|
|
266
|
-
### 10. style/class on components are now regular props
|
|
267
|
-
|
|
268
|
-
Before, it was possible to do this in a template:
|
|
269
|
-
|
|
270
|
-
```xml
|
|
271
|
-
<Child style="..." class="..."/>
|
|
272
|
-
```
|
|
273
|
-
(or with `t-att-style` and `t-att-class`). This does no longer work, as they are
|
|
274
|
-
now considered normal props.
|
|
275
|
-
|
|
276
|
-
Rationale: with the move to fragments, the semantics of where the style/class
|
|
277
|
-
attribute should be set is unclear. Also, it is actually very hard to implement
|
|
278
|
-
properly, in particular with higher order components. And another issue is that
|
|
279
|
-
it (slightly) breaks the encapsulation of behaviour from the `Child` component
|
|
280
|
-
perspective.
|
|
281
|
-
|
|
282
|
-
Migration: each component that wishes to be customized should explicitely add
|
|
283
|
-
the `class` and `style` attributes in its template. Also, the parent component
|
|
284
|
-
should be aware that since we are talking about props, it should be a javascript expression:
|
|
285
|
-
|
|
286
|
-
In parent:
|
|
287
|
-
|
|
288
|
-
```xml
|
|
289
|
-
<Child class="'o_my_god'"/>
|
|
290
|
-
```
|
|
291
|
-
and in child:
|
|
292
|
-
|
|
293
|
-
```xml
|
|
294
|
-
<div t-att-class="props.class">
|
|
295
|
-
...
|
|
296
|
-
</div>
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### 11. components can no longer be mounted with position=self
|
|
300
|
-
|
|
301
|
-
Rationale: this is due to the implementation of owl 2 virtual dom. The hack
|
|
302
|
-
necessary to support position=self does not work. This position also is not
|
|
303
|
-
compatible with the fact that a component can have a root `<div>` then later,
|
|
304
|
-
change it to something else, or even a text node.
|
|
305
|
-
|
|
306
|
-
Migration: no real way to do the same. Owl application needs to be appended or
|
|
307
|
-
prepended in something, maybe a `div`. Remember that you the root component
|
|
308
|
-
can have multiple roots
|
|
309
|
-
|
|
310
|
-
Documentation:
|
|
311
|
-
- [Fragments](doc/reference/templates.md#fragments)
|
|
312
|
-
- [Mounting a component](doc/reference/app.md#mount-helper)
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
### 13. Portal does no longer transfer DOM events
|
|
316
|
-
|
|
317
|
-
In Owl 1, a Portal component would listen to events emitted on its portalled
|
|
318
|
-
child, and redispatch them on itself. It no longer works.
|
|
319
|
-
|
|
320
|
-
Rationale: Portal now supports an arbitrary content (so, more than one child,
|
|
321
|
-
and potentially no html element), so it is already unclear what it should listen
|
|
322
|
-
to. Also, redispatching events was an hack. And this changes allows the portal
|
|
323
|
-
to render itself as a text node, which is nice. This is also in line with the
|
|
324
|
-
fact that modern Owl moves toward using callback instead of `t-on` for communication.
|
|
325
|
-
|
|
326
|
-
Migration: use callback if possible to communicate. Otherwise, use a sub env.
|
|
327
|
-
|
|
328
|
-
### 14. Portal does render as an empty text node instead of `<portal/>`
|
|
329
|
-
|
|
330
|
-
That is pretty nice. No real migration needed.
|
|
331
|
-
|
|
332
|
-
### 15. Context is removed
|
|
333
|
-
|
|
334
|
-
Context was an abstraction in Owl that was used to define some reactive state
|
|
335
|
-
and to let some components subscribe to it, then only them would be rerendered
|
|
336
|
-
if the context was updated. This has been removed.
|
|
337
|
-
|
|
338
|
-
Rationale: first, the Context api and code was kind of awkward, which is a sign
|
|
339
|
-
that the abstraction is not well thought. But the good news is that it is actually
|
|
340
|
-
completely replaced by the new reactivity system, which is even more powerful,
|
|
341
|
-
since it can tracks changes key by key.
|
|
342
|
-
|
|
343
|
-
Migration: replace all uses of Context with the new reactivity system.
|
|
344
|
-
|
|
345
|
-
```js
|
|
346
|
-
// somewhere, maybe in a service, or in the global env
|
|
347
|
-
const context = observe({some: "state"})
|
|
348
|
-
|
|
349
|
-
// in a component that would previously get a reference to the context:
|
|
350
|
-
|
|
351
|
-
setup() {
|
|
352
|
-
this.context = useState(context);
|
|
353
|
-
// now the component is subscribed to the context and will react to any
|
|
354
|
-
// change for any key read by the component, and only those changes
|
|
355
|
-
}
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
### 16. `env` is now totally empty
|
|
359
|
-
|
|
360
|
-
In Owl 1, the `env` object had to contain a QWeb instance. This was the way
|
|
361
|
-
components would get a reference to their template function. It no longer works
|
|
362
|
-
that way: the `env` object is now totally empty (from the perspective of Owl).
|
|
363
|
-
It is now a user space concept, useful for the application.
|
|
364
|
-
|
|
365
|
-
Rationale: first, there is no longer a QWeb class. Also, this changes simplifies
|
|
366
|
-
the way components works internally.
|
|
367
|
-
|
|
368
|
-
Migration: there is no proper way to get an equivalent. The closest is to get
|
|
369
|
-
a reference to the root App using `this.__owl__.app`. If you need to do this,
|
|
370
|
-
let us know. If this is a legitimate usecase, we may add a `useApp` hook.
|
|
371
|
-
|
|
372
|
-
Documentation: [Environment](doc/reference/environment.md)
|
|
373
|
-
|
|
374
|
-
### 17. `t-component` no longer accepts strings
|
|
375
|
-
|
|
376
|
-
In owl 1, we could write this:
|
|
377
|
-
|
|
378
|
-
```xml
|
|
379
|
-
<t t-component="Coucou"/>
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
This meant that Owl would look for the component class like this: `components["Coucou"]`,
|
|
383
|
-
so, essentially equivalent to `<Coucou/>`. In Owl 2, the `t-component` directive
|
|
384
|
-
is assumed to be an expression evaluating to a component class:
|
|
385
|
-
|
|
386
|
-
```js
|
|
387
|
-
class Parent extends Component {
|
|
388
|
-
static template = xml`<t t-component="Child"/>`;
|
|
389
|
-
Child = Child;
|
|
390
|
-
}
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
Rationale: it simply seems more consistent with the way directive works. Also,
|
|
394
|
-
the implementation is slightly simpler.
|
|
395
|
-
|
|
396
|
-
Migration: simply using `constructor.components.Coucou` instead of `Coucou` will
|
|
397
|
-
do the trick.
|
|
398
|
-
|
|
399
|
-
Documentation: [Component](doc/reference/component.md#dynamic-sub-components)
|
|
400
|
-
|
|
401
|
-
### 18. most exports are exported at top level
|
|
402
|
-
|
|
403
|
-
Most exports are flattened: for ex, `onMounted` is in owl, not in `owl.hooks`.
|
|
404
|
-
|
|
405
|
-
Rationale: this makes it easier to work with, instead of importing stuff from
|
|
406
|
-
`owl`, then `owl.hooks` and `owl.tags` for example.
|
|
407
|
-
|
|
408
|
-
Migration: all import code simply need to be slightly adapted.
|
|
409
|
-
|
|
410
|
-
### 19. Properties are no longer set as attributes
|
|
411
|
-
|
|
412
|
-
Formerly, html properties `<input type="checkbox" t-att-checked="blah"/>` were
|
|
413
|
-
set as property and as attribute, so, they would be visible in the DOM:
|
|
414
|
-
`<input type="checkbox" checked="blah"/>`. Now, they are treated as property only:
|
|
415
|
-
`<input type="checkbox"/>`.
|
|
416
|
-
|
|
417
|
-
Rationale: this is actually simple to do, is faster, and makes more sense to me.
|
|
418
|
-
|
|
419
|
-
### 20. `t-foreach` should always have a corresponding `t-key`
|
|
420
|
-
|
|
421
|
-
It was possible in Owl 1 to write a `t-foreach` without a `t-key`. In that case,
|
|
422
|
-
the index was used as key. Since it was clearly a possible bug, Owl 1 had a
|
|
423
|
-
warning in some cases, when it could detect that there was definitely not a `t-key`.
|
|
424
|
-
However, this was imperfect, and in some cases no warning was displayed. In Owl 2,
|
|
425
|
-
the tag with a `t-foreach` has to have a corresponding `t-key`.
|
|
426
|
-
|
|
427
|
-
Rationale: this makes it easier to avoid bugs.
|
|
428
|
-
|
|
429
|
-
Migration: simply move the `t-key` to the tag with the `t-foreach`. If this is
|
|
430
|
-
a situation where there is really not a need for a `t-key`, you can still add
|
|
431
|
-
it with the `_index` suffix:
|
|
432
|
-
|
|
433
|
-
```xml
|
|
434
|
-
<div t-foreach="items" t-as="item" t-key="item_index">
|
|
435
|
-
...
|
|
436
|
-
</div>
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
### 21. `EventBus` api changed: it is now an `EventTarget`
|
|
440
|
-
|
|
441
|
-
In Owl 1, the `EventBus` class was done manually, with a custom API. In Owl 2,
|
|
442
|
-
it simply extends `EventTarget` (the native Dom class), so its implementation
|
|
443
|
-
is basically only 5 lines long. This means that it has now the usual DOM interface:
|
|
444
|
-
|
|
445
|
-
```js
|
|
446
|
-
bus.addEventListener('event-name', callback);
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
Rationale: it makes it easier to have just one interface to remember, it makes
|
|
450
|
-
the code simpler
|
|
451
|
-
|
|
452
|
-
Migration: most bus methods need to be adapted. So, `bus.on("event-type", owner, (info) => {...})` has to be
|
|
453
|
-
rewritten like this: `bus.addEventListener("event-type", (({detail: info}) => {...}).bind(owner))`.
|
|
454
|
-
|
|
455
|
-
Do not forget to similarly replace `bus.off(...)` by `bus.removeEventListener(...)`
|
|
456
|
-
|
|
457
|
-
Documentation: [EventBus](doc/reference/utils.md#eventbus)
|
|
458
|
-
|
|
459
|
-
### 22. `Store` is removed
|
|
460
|
-
|
|
461
|
-
The Store system had been abandoned in owl 2.
|
|
462
|
-
|
|
463
|
-
Rationale: first, it was complicated to maintain. Second, it was not really
|
|
464
|
-
used in Odoo. Finally, the new reactivity system seems to be a pretty good basis
|
|
465
|
-
to write a store, and it should not take much work. Also, this can be done in
|
|
466
|
-
user space (so, not necessarily at the framework level). Another point is that
|
|
467
|
-
the store API was invented before the hooks, then was still a little awkward.
|
|
468
|
-
|
|
469
|
-
Migration:
|
|
470
|
-
- rewrite the code not to use a store
|
|
471
|
-
- probably use the reactivity system instead and build a store class and a few
|
|
472
|
-
hooks on top of it.
|
|
473
|
-
|
|
474
|
-
### 23. `Router` is removed
|
|
475
|
-
|
|
476
|
-
Rationale: Router was not used that much, and it felt like it did not fit in Owl 2.
|
|
477
|
-
Its API needs to be reworked, and we are not confident that it is a good
|
|
478
|
-
experience to use it. Also, it can be done in userspace (it does not need specific
|
|
479
|
-
integration at the framework level)
|
|
480
|
-
|
|
481
|
-
Migration: reimport all missing piece from the code in Owl 1.
|
|
482
|
-
|
|
483
|
-
### 24. transition system is removed
|
|
484
|
-
|
|
485
|
-
Rationale: this was a high ratio cost/value, with a lot of potential for bugs.
|
|
486
|
-
We feel like there should be a way to reimplement in userspace the simple cases.
|
|
487
|
-
|
|
488
|
-
Maybe something like: add a `t-ref` in the template, and define a hook `useFadeOut`
|
|
489
|
-
that takes the ref, and add a fadeout class at initial render, then in mounted,
|
|
490
|
-
wait for a micro tick and remove it.
|
|
491
|
-
|
|
492
|
-
Migration: try to reimplement it manually.
|
|
493
|
-
|
|
494
|
-
### 25. no more global components or templates
|
|
495
|
-
|
|
496
|
-
It was possible in Owl 1 to register globally a component or a template. This is
|
|
497
|
-
no longer the case in Owl 2.
|
|
498
|
-
|
|
499
|
-
Rationale: first, this was a tradeoff: ease of use was gained, but at the cost
|
|
500
|
-
of a higher complexity. Users had to know that there was a magic mechanism. Also,
|
|
501
|
-
it was not used much in practice, and the cost of having to import manually components
|
|
502
|
-
is low. Finally, this can be mostly done in user space (for example, by subclassing
|
|
503
|
-
`Component`).
|
|
504
|
-
|
|
505
|
-
Migration: import manually all required global components, or find a way to organize
|
|
506
|
-
the code to do it.
|
|
507
|
-
|
|
508
|
-
### 26. `AsyncRoot` utility component is removed
|
|
509
|
-
|
|
510
|
-
Rationale: it was difficult to understand, never used, and not really useful.
|
|
511
|
-
It seems better to control the asynchrony of an application by simply controlling
|
|
512
|
-
how/when the state is updated, and how each component is loading/updating itself.
|
|
513
|
-
|
|
514
|
-
Migration: remove the `AsyncRoot` component, then possibly, reorganize the code
|
|
515
|
-
to fetch data in a higher order component, and using a `t-if/t-else` to display
|
|
516
|
-
either a fallback when the data is not ready, or the actual component with data
|
|
517
|
-
as props. If there is no escape, and `AsyncRoot` is needed, please reach out to
|
|
518
|
-
us so we can study this usecase.
|
|
519
|
-
|
|
520
|
-
### 27. `useChildSubEnv` (only applies to child components)
|
|
521
|
-
|
|
522
|
-
In Owl, a call to `useSubEnv` would define a new environment for the children
|
|
523
|
-
AND the component. It is very useful, but in some cases, one only need to update
|
|
524
|
-
the children component environment. This can now be done with a new hook:
|
|
525
|
-
[`useChildSubEnv`](doc/reference/hooks.md#usesubenv-and-usechildsubenv)
|
|
526
|
-
|
|
527
|
-
### 28. `env` is now frozen
|
|
528
|
-
|
|
529
|
-
In Owl 2, the `env` object is frozen. It can no longer be modified (structurally)
|
|
530
|
-
arbitrarily.
|
|
531
|
-
|
|
532
|
-
Rationale: it seems like the `env` object purpose is to have a global channel of
|
|
533
|
-
communication between components. It is however scary if anyone can add something
|
|
534
|
-
to it. The usual use case is to add something to the environment for some child
|
|
535
|
-
components. This use case still works with `useSubEnv`.
|
|
536
|
-
|
|
537
|
-
Migration: use `useSubEnv` instead of writing directly to the env. Also, note
|
|
538
|
-
that the environment given to the App can initially contain anything.
|
|
539
|
-
|
|
540
|
-
Documentation: [Environment](doc/reference/environment.md)
|
|
541
|
-
|
|
542
|
-
### 29. `t-ref` does not work on component
|
|
543
|
-
|
|
544
|
-
Before, `t-ref` could be used to get a reference to a child component. It no
|
|
545
|
-
longer works.
|
|
546
|
-
|
|
547
|
-
Rationale: the possibility of having a ref to a child component breaks the
|
|
548
|
-
encapsulation provided by Owl components: a child component now has a private
|
|
549
|
-
and a public interface. Another issue is that it may be unclear when the ref
|
|
550
|
-
should be set: is the component active on setup, or on mounted? Also, it is
|
|
551
|
-
kind of awkward to implement.
|
|
552
|
-
|
|
553
|
-
Migration: the `env` and `props` should provide a communication channel wide enough:
|
|
554
|
-
the sub component can expose its public API by calling a callback at the proper
|
|
555
|
-
timing, or by triggering an event.
|
|
556
|
-
|
|
557
|
-
### 30. `t-on` does not accept expressions, only functions
|
|
558
|
-
|
|
559
|
-
In Owl 1, it was possible to define simple expressions inline, in a template:
|
|
560
|
-
|
|
561
|
-
```xml
|
|
562
|
-
<button t-on-click="state.value = state.value + 1">blabla</button>
|
|
563
|
-
<button t-on-click="someFunction(someVar)">blabla</button>
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
This does not work anymore. Now, the `t-on` directive assumes that what it get is
|
|
567
|
-
a function.
|
|
568
|
-
|
|
569
|
-
Rationale: the fact that owl 1 had to support expressions meant that it was not
|
|
570
|
-
possible to properly inject the event in general. With this restriction, Owl 2
|
|
571
|
-
can support more general use cases. Also, the examples above can simply be
|
|
572
|
-
wrapped in a lambda function.
|
|
573
|
-
|
|
574
|
-
Migration: use lambda functions. For example, the two examples above can be
|
|
575
|
-
adapted like this:
|
|
576
|
-
|
|
577
|
-
```xml
|
|
578
|
-
<button t-on-click="() => state.value = state.value + 1">blabla</button>
|
|
579
|
-
<button t-on-click="() => this.someFunction(someVar)">blabla</button>
|
|
580
|
-
```
|
|
581
|
-
|
|
582
|
-
Documentation: [Event Handling](doc/reference/event_handling.md)
|
|
583
|
-
|
|
584
|
-
### 31. components can now have arbitrary content
|
|
585
|
-
|
|
586
|
-
Before Owl 2, components had to limit themselves to one single htmlelement as
|
|
587
|
-
root. Now, the content is arbitrary: it can be empty, or multiple html elements.
|
|
588
|
-
So, the following template works for components:
|
|
589
|
-
|
|
590
|
-
```xml
|
|
591
|
-
<div>1</div>
|
|
592
|
-
<div>2</div>
|
|
593
|
-
hello
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
Documentation: [Fragments](doc/reference/templates.md#fragments)
|
|
597
|
-
|
|
598
|
-
### 32. `renderToString` on QWeb has been removed
|
|
599
|
-
|
|
600
|
-
Rationale: the `renderToString` function was a qweb method, which made sense because
|
|
601
|
-
the qweb instance knew all templates. But now, the closest analogy is the `App`
|
|
602
|
-
class, but it is not as convenient, since the `app` instance is no longer visible
|
|
603
|
-
to components (while before, `qweb` was in the environment).
|
|
604
|
-
|
|
605
|
-
Also, this can easily be done in userspace, by mounting a component in a div. For example:
|
|
606
|
-
|
|
607
|
-
```js
|
|
608
|
-
export async function renderToString(template, context) {
|
|
609
|
-
class C extends Component {
|
|
610
|
-
static template = template;
|
|
611
|
-
setup () {
|
|
612
|
-
Object.assign(this, context);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
const div = document.createElement('div');
|
|
616
|
-
document.body.appendChild(div);
|
|
617
|
-
const app = new App(C);
|
|
618
|
-
await app.mount(div);
|
|
619
|
-
const result = div.innerHTML;
|
|
620
|
-
app.destroy();
|
|
621
|
-
div.remove();
|
|
622
|
-
return result;
|
|
623
|
-
}
|
|
624
|
-
```
|
|
625
|
-
|
|
626
|
-
The function above works for most cases, but is asynchronous. An alternative
|
|
627
|
-
function could look like this:
|
|
628
|
-
|
|
629
|
-
```js
|
|
630
|
-
const { App, blockDom } = owl;
|
|
631
|
-
const app = new App(Component); // act as a template repository
|
|
632
|
-
|
|
633
|
-
function renderToString(template, context = {}) {
|
|
634
|
-
app.addTemplate(template, template, { allowDuplicate: true });
|
|
635
|
-
const templateFn = app.getTemplate(template);
|
|
636
|
-
const bdom = templateFn(context, {});
|
|
637
|
-
const div = document.createElement('div')
|
|
638
|
-
blockDom.mount(bdom, div);
|
|
639
|
-
return div.innerHTML;
|
|
640
|
-
}
|
|
641
|
-
```
|
|
642
|
-
|
|
643
|
-
This is a synchronous function, so it will not work with components, but it should
|
|
644
|
-
be useful for most simple templates.
|
|
645
|
-
|
|
646
|
-
Also note that these two examples do not translate their templates. To do that,
|
|
647
|
-
they need to be modified to pass the proper translate function to the `App`
|
|
648
|
-
configuration.
|
|
649
|
-
|
|
650
|
-
### 33. Portal are now defined with `t-portal`
|
|
651
|
-
|
|
652
|
-
Before Owl 2, one could use the `Portal` component by importing it and using it.
|
|
653
|
-
Now, it is no longer available. Instead, we can simply use the `t-portal` directive:
|
|
654
|
-
|
|
655
|
-
```xml
|
|
656
|
-
<div>
|
|
657
|
-
some content
|
|
658
|
-
<span t-portal="'body'">
|
|
659
|
-
portalled content
|
|
660
|
-
</span>
|
|
661
|
-
<div>
|
|
662
|
-
```
|
|
663
|
-
|
|
664
|
-
Rationale: it makes it slightly simpler to use (just need the directive, instead
|
|
665
|
-
of having to import and use a sub component), it makes the implementation slightly
|
|
666
|
-
simpler as well. Also, it prevents subclassing the Portal component, which could
|
|
667
|
-
be dangerous, since it is really doing weird stuff under the hood, and could
|
|
668
|
-
easily be broken inadvertendly.
|
|
669
|
-
|
|
670
|
-
### 34. `debounce` utility function has been removed
|
|
671
|
-
|
|
672
|
-
Rationale: it did not really help that much, is available as utility function
|
|
673
|
-
elsewhere, so, we decided to have a smaller footprint by focusing Owl on what
|
|
674
|
-
it does best.
|
|
675
|
-
|
|
676
|
-
### 35. `render` method does not return a promise anymore
|
|
677
|
-
|
|
678
|
-
Rationale: using the `render` method directly and waiting for it to complete
|
|
679
|
-
was slightly un-declarative. Also, it can be done using the lifecycle hooks
|
|
680
|
-
any way.
|
|
681
|
-
|
|
682
|
-
Migration: if necessary, one can use the lifecycle hooks to execute code after
|
|
683
|
-
the next mounted/patched operation.
|
|
684
|
-
|
|
685
|
-
### 36. `catchError` method is replaced by `onError` hook
|
|
686
|
-
|
|
687
|
-
The `catchError` method was used to provide a way to components to handle errors
|
|
688
|
-
occurring during the component lifecycle. This has been replaced by a `onError`
|
|
689
|
-
hook, with a similar API.
|
|
690
|
-
|
|
691
|
-
Rationale: `catchError` felt a little big awkward, when most of the way we
|
|
692
|
-
interact with componentss is via hooks. Using hooks felt more natural and
|
|
693
|
-
consistent.
|
|
694
|
-
|
|
695
|
-
Migration: mostly replace all `catchError` methods by `onError` hooks in the
|
|
696
|
-
`setup` method.
|
|
697
|
-
|
|
698
|
-
Documentation: [Error Handling](doc/reference/error_handling.md)
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
## 37. Support for inline css (`css` tag and static `style`) has been removed
|
|
702
|
-
|
|
703
|
-
Rationale: Owl tries to focus on what it does best, and supporting inline css
|
|
704
|
-
was not a priority. It used to support some simplified scss language, but it
|
|
705
|
-
was feared that it would cause more trouble than it was worth. Also, it seems
|
|
706
|
-
like it can be done in userspace.
|
|
707
|
-
|
|
708
|
-
Migration: it seems possible to implement an equivalent solution using hooks. A
|
|
709
|
-
simple implementation could look like this:
|
|
710
|
-
|
|
711
|
-
```js
|
|
712
|
-
let cache = {};
|
|
713
|
-
|
|
714
|
-
function useStyle(css) {
|
|
715
|
-
if (!css in cache) {
|
|
716
|
-
const sheet = document.createElement("style");
|
|
717
|
-
sheet.innerHTML = css;
|
|
718
|
-
cache[css] = sheet;
|
|
719
|
-
document.head.appendChild(sheet);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
```
|
|
723
|
-
|
|
724
|
-
## 38. `t-raw` directive has been removed (replaced by `t-out`)
|
|
725
|
-
|
|
726
|
-
To match the Odoo qweb server implementation, Owl does no longer implement `t-raw`.
|
|
727
|
-
It is replaced by the `t-out` directive, which is safer: it requires the data
|
|
728
|
-
to be marked explicitely as markup if it is to be inserted without escaping.
|
|
729
|
-
Otherwise, it will be escaped (just like `t-esc`).
|
|
730
|
-
|
|
731
|
-
Migration: replace all `t-raw` uses by `t-out`, and uses the `markup` function
|
|
732
|
-
to mark all the js values.
|
|
733
|
-
|
|
734
|
-
Documentation: [Outputting data](doc/reference/templates.md#outputting-data)
|
|
735
|
-
|
|
736
|
-
## 39. `browser` object has been removed
|
|
737
|
-
|
|
738
|
-
Rationale: the `browser` object caused more trouble than it was worth. Also, it
|
|
739
|
-
seems like this should be done in user space, not at the framework level.
|
|
740
|
-
|
|
741
|
-
Migration: code should just be adapted to either use another browser object,
|
|
742
|
-
or to use native browser function (and then, just mock them directly).
|
|
743
|
-
|
|
744
|
-
## 40. Rendering a component does not necessarily render child components
|
|
745
|
-
|
|
746
|
-
Before, if one had the following component tree:
|
|
747
|
-
|
|
748
|
-
```mermaid
|
|
749
|
-
graph TD;
|
|
750
|
-
A-->B;
|
|
751
|
-
A-->C;
|
|
752
|
-
```
|
|
753
|
-
|
|
754
|
-
when `A` would render, it would also render `B` and `C`. Now, in Owl 2, it will
|
|
755
|
-
(shallow) compare the before and after props, and `B` or `C` will only be rerendered
|
|
756
|
-
if their props have changed.
|
|
757
|
-
|
|
758
|
-
Now, the question is what happens if the props have changed, but in a deeper way?
|
|
759
|
-
In that case, Owl will know, because each props are now reactive. So, if some
|
|
760
|
-
inner value read by `B` was changed, then only `B` will be updated.
|
|
761
|
-
|
|
762
|
-
Rationale: This was just not possible in Owl 1, but it now possible. This is
|
|
763
|
-
due to the rewriteof the underlying rendering engine and the reactivity
|
|
764
|
-
system. The goal is to have a big performance boost in large screen with many
|
|
765
|
-
components: now Owl only rerender what is strictly useful.
|
|
766
|
-
|