[IMP] component: allow multiple mount/unmount

closes #258
This commit is contained in:
Géry Debongnie
2019-08-22 13:32:53 +02:00
parent eaf912bed7
commit e5b1ba24d8
3 changed files with 76 additions and 4 deletions
+2
View File
@@ -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.
+13 -4
View File
@@ -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)) {
+61
View File
@@ -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"]);
});
});