mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] component: allow fragments in method mount
It is now possible to mount components in fragments closes #494
This commit is contained in:
@@ -239,7 +239,7 @@ We explain here all the public methods of the `Component` class.
|
|||||||
|
|
||||||
- **`mount(target)`** (async): this is the main way a
|
- **`mount(target)`** (async): this is the main way a
|
||||||
component is added to the DOM: the root component is mounted to a target
|
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
|
created as well. Most applications will need to call `mount` exactly once, on
|
||||||
the root component.
|
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
|
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.
|
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
|
- **`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
|
method can be used. Most applications should not call `unmount`, this is more
|
||||||
useful to the underlying component system.
|
useful to the underlying component system.
|
||||||
|
|||||||
@@ -281,12 +281,12 @@ export class Component<T extends Env, Props extends {}> {
|
|||||||
*
|
*
|
||||||
* Note that a component can be mounted an unmounted several times
|
* 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__;
|
const __owl__ = this.__owl__;
|
||||||
if (__owl__.isMounted) {
|
if (__owl__.isMounted) {
|
||||||
return Promise.resolve();
|
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.`;
|
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)`;
|
message += `\nMaybe the DOM is not ready yet? (in that case, you can use owl.utils.whenReady)`;
|
||||||
throw new Error(message);
|
throw new Error(message);
|
||||||
|
|||||||
@@ -91,6 +91,17 @@ describe("basic widget properties", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<div>content</div>");
|
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 () => {
|
test("display a nice message if mounted on a non existing node", async () => {
|
||||||
class SomeWidget extends Component<any, any> {
|
class SomeWidget extends Component<any, any> {
|
||||||
static template = xml`<div>content</div>`;
|
static template = xml`<div>content</div>`;
|
||||||
|
|||||||
Reference in New Issue
Block a user