mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
@@ -149,6 +149,8 @@ We explain here all the public methods of the `Component` class.
|
||||
is asynchronous, since each children need to be created as well. Most applications
|
||||
will need to call `mount` exactly once, on the root component.
|
||||
|
||||
Note that a component can be mounted and unmounted multiple times if needed.
|
||||
|
||||
- **`unmount()`**: in case a component need 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.
|
||||
|
||||
@@ -265,14 +265,23 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
|
||||
*
|
||||
* This should only be done if the component was created manually. Components
|
||||
* created declaratively in templates are managed by the Owl system.
|
||||
*
|
||||
* Note that a component can be mounted an unmounted several times
|
||||
*/
|
||||
async mount(target: HTMLElement): Promise<void> {
|
||||
const vnode = await this.__prepare();
|
||||
if (this.__owl__.isDestroyed) {
|
||||
// component was destroyed before we get here...
|
||||
if (this.__owl__.isMounted) {
|
||||
return;
|
||||
}
|
||||
this.__patch(vnode);
|
||||
if (this.__owl__.renderId === 1) {
|
||||
// we use the fact that renderId === 1 as a way to determine that the
|
||||
// component is mounted for the first time
|
||||
const vnode = await this.__prepare();
|
||||
if (this.__owl__.isDestroyed) {
|
||||
// component was destroyed before we get here...
|
||||
return;
|
||||
}
|
||||
this.__patch(vnode);
|
||||
}
|
||||
target.appendChild(this.el!);
|
||||
|
||||
if (document.body.contains(target)) {
|
||||
|
||||
@@ -3950,3 +3950,64 @@ describe("top level sub widgets", () => {
|
||||
expect(fixture.innerHTML).toBe("<div>CHILD 2</div>");
|
||||
});
|
||||
});
|
||||
|
||||
describe("unmounting and remounting", () => {
|
||||
test("widget can be unmounted and remounted", async () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="MyWidget">Hey</div>
|
||||
</templates>`);
|
||||
|
||||
const steps: string[] = [];
|
||||
class MyWidget extends Widget {
|
||||
async willStart() {
|
||||
steps.push("willstart");
|
||||
}
|
||||
mounted() {
|
||||
steps.push("mounted");
|
||||
}
|
||||
willUnmount() {
|
||||
steps.push("willunmount");
|
||||
}
|
||||
}
|
||||
|
||||
const w = new MyWidget(env);
|
||||
await w.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div>Hey</div>");
|
||||
expect(steps).toEqual(["willstart", "mounted"]);
|
||||
|
||||
w.unmount();
|
||||
expect(fixture.innerHTML).toBe("");
|
||||
expect(steps).toEqual(["willstart", "mounted", "willunmount"]);
|
||||
|
||||
await w.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div>Hey</div>");
|
||||
expect(steps).toEqual(["willstart", "mounted", "willunmount", "mounted"]);
|
||||
});
|
||||
|
||||
test("widget can be mounted twice without ill effect", async () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="MyWidget">Hey</div>
|
||||
</templates>`);
|
||||
|
||||
const steps: string[] = [];
|
||||
class MyWidget extends Widget {
|
||||
async willStart() {
|
||||
steps.push("willstart");
|
||||
}
|
||||
mounted() {
|
||||
steps.push("mounted");
|
||||
}
|
||||
willUnmount() {
|
||||
steps.push("willunmount");
|
||||
}
|
||||
}
|
||||
|
||||
const w = new MyWidget(env);
|
||||
await w.mount(fixture);
|
||||
await w.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div>Hey</div>");
|
||||
expect(steps).toEqual(["willstart", "mounted"]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user