Before this commit, Owl could not detect that the underlying component
in a template such as <t t-component="{{state.child}}"/> was changing,
if the two components have the same tag as root element.
This is because the reconciliation is done at the vdom level, which does
not know about components. To solve this, one could use a t-key to make
sure owl can make the difference.
With this commit, we can simply use our knowledge of the fact that we are
dealing with a dynamic component and autogenerate a suitable key.
closes#623
the low level method htmlelement.classList.add does not accept multiple
classes in one string, which is why, in owl, the expression
`<div t-att-class="{'a b c': value}" />`
did not work as one might expect. It is however very convenient in real
life templates, so this commit improve owl by adding support for this
feature.
closes#813
Before this commit, the error handling code simply destroyed the
application whenever an unhandled error occured in the owl rendering
process. This is perfectly fine, except that since the application is
potentially corrupted, the destroy code may crash as well. We simply
catch those errors to avoid shadowing the main issue.
closes#866
Before this commit, owl was erroneously defining default slots in most
cases, even though they are empty. The problem occurs when the content
of a component slots is a t-set-slot, and we remove that, then use the
rest as default slots, even though it is only reduced to a set of text
nodes.
With this commit, we only consider the content as default content if it
is not only a sequence of text nodes containing only spaces.
closes#882
The templates contained in a slot have to be rendered with the current
scope, but during the rendering of the sub component, which happens
later (after the willStart for the sub component). Therefore, we need to
save the scope that should be used for the slots, so we can access the
proper variables. This was done using an Object.assign() statement,
which is actually only a shallowclone for the own properties.
In this commit, we properly copy all the properties for the current
scope, even those contained in the prototype.
closes#855
Before this commit, it was not possible to set the value of a select tag
by using the t-att-value attribute.
Doing so is not actually trivial because of the way the vdom works: it
processes the node attributes before its children are created, which
means that the vdom code tries to set the initial value of the select
before its children are created, which means that it is ignored. To make
it work, I added a node create hook which is called after the children
are completely processed.
closes#873
Before this commit, using an expression such as "{machin}" was compiled
in qweb into "{scope['machin']}" which is not valid.
With this commit, we instead transform it into "{machin:
scope['machin']}".
closes#885
Before this commit, props and t-props were computed like
`Object.assign(props, t_props)`.
Now, it computes like `Object.assign(t_props, props)` so props will
override t-props.
closes https://github.com/odoo/owl/issues/886
Backport of odoo/odoo@e4834fce69
There's no way to easily disable / silence this warning, because
multiple tours explicitly opt into debug mode (with good reasons). So
it's not enough to bypass the `mode` setter in the test setup helpers
and set `QWeb.dev` directly (which works for test_main in POS and
main_tests in web), there would also need to be special workarounds in
the 4 modules which set `owl.config.mode` based on the session's debug
mode.
I'm not sure how useful this warning is: it defaults to `false` so the
only situation in which this would be relevant would be for a
third-party to use Owl *and* explicitly enable the debug mode
in-source *and* forget to remove it when deploying to production *and*
look at their console.
Before this commit, the error handling process was too naive: once an
error occurs in a rendering, owl catches it, looks for a component that
implements the catchError method, then calls it.
However, in real life, we sometimes need to rethrow that error (or
another one) to propagate the error to some parent handler. This error
needs to be handled by the closest parent component that implements
catchError.
This is what this commit implements: it wraps the catchError call in a
try/catch, then in case of errors, try to handle it by a parent.
Have a t-call within a t-set-slot of a component.
The called template has a t-component directive.
It should be like:
```xml
<t t-name="Zero">
<Slotted>
<t t-call="someTemplate" />
</Slotted>
</t>
<t t-name="someTemplate">
<SomeComponent />
</t>
```
Before this commit, the parent of SomeComponent was the Zero component
After this commit, the parent of SomeComponent is the Slotted Component as it should be
closes#862
Before this commit, params in paths had to be be between slashes and
comprise the entirety of the contents between those slashes (eg:
`/books/{{id}}/{{name}}`)
This is unnecessarily restrictive. This commit removes this restriction,
which allows for paths such as:
- `/books/{{id}}-{{name}}`
- `#books&id={{id}}&name={{name}}`
among others
closes#858
Previously, the order of resolution was:
- components defined on the class of the current component
- components defined on the QWeb instance
- the current instance's context
This is unnatural because it doesn't go from most specific to least, as
the current instance's context is the most specific. This is also
fragile, as adding components to the QWeb instance can break unrelated
components.
This commit fixes that by making the lookup start with the current
component's context instead
Release script errase dist folder
closes#793
Release can only be done on master branch
closes#829
Update the playground owl version on release
closes#814
Add logError method in release to show messages in red.
Check-formatting command added to the release process.
The initial problem solved by this commit is that it was possible to get
into a situation where a mounting/rendering was started, then the component was
updated, but then another mounting operation begins, and it tries to
reuse the previous rendering operation, which is no longer uptodate.
The underlying issue is that Owl did not track properly the various
internal state change of a component. These issue should be solved by
the introduction of the status enum, which currently tracks 6 possible
states:
- CREATED
- WILLSTARTED
- RENDERED
- MOUNTED
- UNMOUNTED
- DESTROYED
This status number replaces the isMounted and isDestroyed boolean flags.
It has the advantage of making sure that the component is in a
consistent state (it is no longer possible to be destroyed and mounted,
for example)
Another advantage is that it gives us an easy way to track the fact that
a component has been rendered, but is not in the DOM. This is a subtle
situation where some various events can happen, and we need to be able
to react to that case.
Note that there is a change of behaviour: if a component is mounted in a
specific target, then before the mounting is complete, the component is
mounted in another target, we no longer reject the first mounting
operation.
The QWeb expression parser use an object as a mapping between some
strings and the desired output in the compiled template. However, as we
should all know, objects are not Maps, they have some additional
properties, such as "constructor" or "hasOwnProperty".
The simple solution is to make sure the mapping object does not have
anything in its prototype chain to pollute its purpose.
closes#835
From the beginning, Owl was designed to only call event handler on
components that are mounted in the DOM. The main benefit is that if a
component is destroyed, we are guaranteed to not execute any useless (or
potentially dangerous code).
However, there is one downside: if a component tree is being mounted,
and a child component trigger an event in its mounted hook, then it
cannot be caught by the parent, since the parent is technically not yet
mounted.
This may not be a good situation, but the point is that Owl
unnecessarily prevent the handler to be called.
We can fix this issue by simply checking if the component is not destroyed
instead of checking that it is mounted.
closes#809
This commit makes sure that Owl does not crash when a component is
created, then updated (for example, with a (observed) state change), and
then, some moment later, mounted.
The initial render is not useful, because it is not linked to a mounting
action anyway. And it caused issues such as a crash when Owl tried to
patch it to a non existing target
# v1.2.2
This is just a small bug fix release, because we need it in Odoo.
Bug fix: allow renderings for detached components. Before this release, Owl
ignored renderings in some cases if a component is detached. We now still render
it, because it is important in some cases.
This commit tries to improve the interactions involving unmounted
components, or components mounted in an htmelement which is detached
from the main DOM, and rendering actions.
The main example is mounting a component in detached div, to prepare all
children. If we just mount the component, it will work as expected: the
full component tree is rendered in memory, and ready to be really
mounted at the desired target.
However, if before doing that, we update the component and call render
on it (for example, with a change in an observed state), then this
rendering will be ignored, and therefore, the full subcomponent tree is
not uptodate.
This commit will also solve another issue in the compatibility layer in
odoo: in the form renderer, we mount components with the adapter in a
div, which is not yet attached to the DOM. We then manually call the
mounted hook when on_attach_callback is called. This means that before
this commit, any change to the components between the initial rendering
and the call to mounted will be ignored.
As a bonus, this commit has the effect of bringing closer the semantics
of render and mount operations, which is certainly good.
closes#823
# Owl v1.2.1
## Changes
- fix: issue with components with shouldUpdate and remounting not rendering
- fix: issue with connected components using onUpdate callback not rendering
- fix: error in todoapp example code
Before this commit, the following scenario could happen:
Suppose that we have a parent component A, connected to a store,
and a child component B, also connected to the store and using
the onUpdate feature.
Then, we remount the A component in some other places and a
rendering is initiated in A. We immediately update the store state.
What happens next is:
- rendering A is done, A internal revid is updated
- store update A (but nothing is done because the state change here
does not modify A)
- rendering B is done (from parent), B internal revid is updated
- store update B, notice internal revid is updated, does not call the
onUpdate function
We then have the B component which has not its internal state updated,
because we did not call its onUpdate function.
The solution is to move the onUpdate call in a "preupdate" event, to be
sure that it is called everytime the store is updated.
closes#816
In some cases, a rendering initiated in some component is then remapped
into a larger rendering initiated by some parent.
If we have some components which implement shouldUpdate to return false,
then the following scenario can happen:
- some parent component is mounted (which triggers a rendering with
force: true => bypass the shouldUpdate)
- some sub component is updated and rerendered, AFTER the previous
rendering goes through it
- the sub component notices that there is an ongoing rendering, and
remaps itself in the parent rendering
Before this commit, the new fiber in the subcomponent does not have
force flag set to true, so the new rendering for the subcomponent does
not go through its own children (if they have shouldUpdate=false)
Another more complex kind of scenaria can happen when a remapped
rendering happen with sub components with dynamic shouldUpdate. The
problem is the same at the end: the new rendering should ignore the
shouldUpdate, to make sure we have the last correct information.
With this commit, we make sure that the flag of the new fiber is set to
true.
closes#818
# Owl v1.2.0
## Changes
- translation fix for terms surrounded by spaces
- fix: properly remount components with shouldUpdate=false
- add: add two new generic hooks: and
- fix: do not skip rendering in components using store and local state (in some cases)
Note that the last change is a pretty significant change: component connected to
a store should be very careful if the data that they represent is deleted, because
they will always be rendered with the current state of the store.
Before this commit, an unwanted behaviour happened when using components
with shouldUpdate implemented, and store/state.
The actual problem is the following: the sub component is using a store,
and shouldupdate. Whenever the component is rendered, it checks if there is an incoming
rendering from the context. If that is the case, it skips the
rendering, because we actually only want to be rendered by the store
rendering (otherwise, we may run into issue with inconsistent data (more
recent data from the context, older data in the component).
However, if shouldUpdate is implemented, then the rendering coming from
the context simply does not arrive.
To fix this, we tried to just force these renderings to go through all children,
regardless of their shouldUpdate status. This actually works, but then
shouldUpdate is ignored, which is an issue in Odoo discuss.
Then, after discussing this situation, we noticed that the context/store
system is actually unsafe: the protection given by the check mentioned
above is in fact fundamentally insufficient: there are other perfectly
valid situations where a rendering can be triggered on the component,
which will bypass the check (for example, an explicit call to
this.render() or a rendering initiated by some parent component) and
cause a crash if the component is not properly defensively written.
Therefore, it is currently mandatory for all components using
context/store to be aware of that, and to protect themselves against
such situations. So, in that regard, the check is not really a
protection, it just helps hiding an unsafe situation anyway and we
decided to remove it.
Note that this is a potentially breaking change: components using a
store and some local state will now be rendered twice in some cases...
closes#799
Components can implement shouldUpdate to return false. In that case,
renderings coming from above should be ignored.
However, if the component was unmounted and is remounted, we actually
need to force a rerendering in that case, so it is mounted, otherwise
the subcomponent is left in unmounted state, which means that rendering
are ignored.
closes#800
# Owl v1.1.1
## Changes
- export object to make utility functions testable
- minor doc improvements and corrections
- fix: make sure owl does not crash in iframe in private mode
This commit performs two tasks:
1. it exports the internal browser object (in owl.browser), for ease of
testing
2. it makes sure that Owl does not crash inside iframes in incognito
mode, because window.localStorage raises an exception in that case
closes#791
The documentation was a bit missleading around which and when css
classes were added to the DOM.
Also added a scss mixin usage exemple.
Co-authored-by: Simon Genin (ges) <ges@odoo.com>