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
|
is asynchronous, since each children need to be created as well. Most applications
|
||||||
will need to call `mount` exactly once, on the root component.
|
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
|
- **`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
|
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.
|
||||||
|
|||||||
@@ -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
|
* This should only be done if the component was created manually. Components
|
||||||
* created declaratively in templates are managed by the Owl system.
|
* 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> {
|
async mount(target: HTMLElement): Promise<void> {
|
||||||
const vnode = await this.__prepare();
|
if (this.__owl__.isMounted) {
|
||||||
if (this.__owl__.isDestroyed) {
|
|
||||||
// component was destroyed before we get here...
|
|
||||||
return;
|
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!);
|
target.appendChild(this.el!);
|
||||||
|
|
||||||
if (document.body.contains(target)) {
|
if (document.body.contains(target)) {
|
||||||
|
|||||||
@@ -3950,3 +3950,64 @@ describe("top level sub widgets", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<div>CHILD 2</div>");
|
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