[FIX] component: allow fragments in method mount

It is now possible to mount components in fragments

closes #494
This commit is contained in:
Géry Debongnie
2019-11-22 14:49:37 +01:00
committed by aab-odoo
parent 7bb04185c7
commit 14db513f3b
3 changed files with 28 additions and 3 deletions
+15 -1
View File
@@ -239,7 +239,7 @@ We explain here all the public methods of the `Component` class.
- **`mount(target)`** (async): this is the main way a
component is added to the DOM: the root component is mounted to a target
HTMLElement. Obviously, this is asynchronous, since each children need to be
HTMLElement (or document fragment). Obviously, this is asynchronous, since each children need to be
created as well. Most applications will need to call `mount` exactly once, on
the root component.
@@ -247,6 +247,20 @@ We explain here all the public methods of the `Component` class.
automatically re-rendered to ensure that changes in its state (or something
in the environment, or in the store, or ...) will be taken into account.
If a component is mounted inside an element or a fragment which is not in the
DOM, then it will be rendered fully, but not active: the `mounted` hooks will
not be called. This is sometimes useful if we want to load an application in
memory. In that case, we need to mount the root component again in an element
which is in the DOM:
```js
const app = new App();
await app.mount(document.createDocumentFragment());
// app is rendered in memory, but not active
await app.mount(document.body);
// app is now visible
```
- **`unmount()`**: in case a component needs to be detached/removed from the DOM, this
method can be used. Most applications should not call `unmount`, this is more
useful to the underlying component system.
+2 -2
View File
@@ -281,12 +281,12 @@ export class Component<T extends Env, Props extends {}> {
*
* Note that a component can be mounted an unmounted several times
*/
async mount(target: HTMLElement): Promise<void> {
async mount(target: HTMLElement | DocumentFragment): Promise<void> {
const __owl__ = this.__owl__;
if (__owl__.isMounted) {
return Promise.resolve();
}
if (!(target instanceof HTMLElement)) {
if (!(target instanceof HTMLElement || target instanceof DocumentFragment)) {
let message = `Component '${this.constructor.name}' cannot be mounted: the target is not a valid DOM node.`;
message += `\nMaybe the DOM is not ready yet? (in that case, you can use owl.utils.whenReady)`;
throw new Error(message);
+11
View File
@@ -91,6 +91,17 @@ describe("basic widget properties", () => {
expect(fixture.innerHTML).toBe("<div>content</div>");
});
test("can be mounted on a documentFragment", async () => {
class SomeWidget extends Component<any, any> {
static template = xml`<div>content</div>`;
}
const widget = new SomeWidget();
await widget.mount(document.createDocumentFragment());
expect(fixture.innerHTML).toBe("");
await widget.mount(fixture);
expect(fixture.innerHTML).toBe("<div>content</div>");
});
test("display a nice message if mounted on a non existing node", async () => {
class SomeWidget extends Component<any, any> {
static template = xml`<div>content</div>`;