diff --git a/src/compile/Compiler.ts b/src/compile/Compiler.ts index 690b837d79..b9dc70b2df 100644 --- a/src/compile/Compiler.ts +++ b/src/compile/Compiler.ts @@ -663,6 +663,10 @@ export default class Compiler { addDeclaration('oncreate', templateProperties.oncreate.value); } + if (templateProperties.onunmount && dom) { + addDeclaration('onunmount', templateProperties.onunmount.value); + } + if (templateProperties.ondestroy && dom) { addDeclaration('ondestroy', templateProperties.ondestroy.value); } diff --git a/src/compile/dom/Block.ts b/src/compile/dom/Block.ts index ca3984b5d7..433446c06e 100644 --- a/src/compile/dom/Block.ts +++ b/src/compile/dom/Block.ts @@ -77,6 +77,7 @@ export default class Block { claim: new CodeBuilder(), hydrate: new CodeBuilder(), mount: new CodeBuilder(), + unmount: new CodeBuilder(), measure: new CodeBuilder(), fix: new CodeBuilder(), animate: new CodeBuilder(), @@ -100,6 +101,10 @@ export default class Block { if (this.key) this.aliases.set('key', this.getUniqueName('key')); this.hasUpdateMethod = false; // determined later + + if (this.compiler.templateProperties.onunmount) { + this.builders.unmount.addLine(`%onunmount.call(#component${this.key ? `, ${this.getUniqueName('key')}` : ''})`); + } } addDependencies(dependencies: Set) { diff --git a/src/compile/dom/index.ts b/src/compile/dom/index.ts index 79645f4081..a8fa7b447b 100644 --- a/src/compile/dom/index.ts +++ b/src/compile/dom/index.ts @@ -201,6 +201,12 @@ export default function dom( }];` )} + ${(templateProperties.onunmount || storeProps.length) && ( + `this._handlers.unmount = [${ + [templateProperties.onunmount && `%onunmount`, storeProps.length && `@removeFromStore`].filter(Boolean).join(', ') + }];` + )} + ${compiler.slots.size && `this._slotted = options.slots || {};`} ${compiler.customElement ? diff --git a/src/shared/index.js b/src/shared/index.js index 898e816beb..d734ececb9 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -15,6 +15,7 @@ export function blankObject() { export function destroy(detach) { this.destroy = noop; + this.fire('unmount'); this.fire('destroy'); this.set = noop; diff --git a/src/validate/js/propValidators/index.ts b/src/validate/js/propValidators/index.ts index cb9a47dac3..76d2ed3f54 100644 --- a/src/validate/js/propValidators/index.ts +++ b/src/validate/js/propValidators/index.ts @@ -3,6 +3,7 @@ import actions from './actions'; import animations from './animations'; import computed from './computed'; import oncreate from './oncreate'; +import onunmount from './onunmount'; import ondestroy from './ondestroy'; import onstate from './onstate'; import onupdate from './onupdate'; @@ -27,6 +28,7 @@ export default { animations, computed, oncreate, + onunmount, ondestroy, onstate, onupdate, diff --git a/src/validate/js/propValidators/onunmount.ts b/src/validate/js/propValidators/onunmount.ts new file mode 100644 index 0000000000..58dc5db18f --- /dev/null +++ b/src/validate/js/propValidators/onunmount.ts @@ -0,0 +1,14 @@ +import usesThisOrArguments from '../utils/usesThisOrArguments'; +import { Validator } from '../../'; +import { Node } from '../../../interfaces'; + +export default function onunmont(validator: Validator, prop: Node) { + if (prop.value.type === 'ArrowFunctionExpression') { + if (usesThisOrArguments(prop.value.body)) { + validator.error( + `'onunmont' should be a function expression, not an arrow function expression`, + prop.start + ); + } + } +} diff --git a/test/runtime/samples/lifecycle-events/Nested.html b/test/runtime/samples/lifecycle-events/Nested.html new file mode 100644 index 0000000000..99edfa147e --- /dev/null +++ b/test/runtime/samples/lifecycle-events/Nested.html @@ -0,0 +1,17 @@ +
+ + \ No newline at end of file diff --git a/test/runtime/samples/lifecycle-events/_config.js b/test/runtime/samples/lifecycle-events/_config.js index 2a9d25564a..c82af470e0 100644 --- a/test/runtime/samples/lifecycle-events/_config.js +++ b/test/runtime/samples/lifecycle-events/_config.js @@ -1,7 +1,12 @@ export default { test(assert, component) { + const nested = component.refs.nested; + + assert.deepEqual(component.events, ['create']); + assert.deepEqual(nested.events, { create: false }); component.destroy(); - assert.deepEqual(component.events, ['create', 'destroy']); + assert.deepEqual(component.events, ['create', 'unmount', 'destroy']); + assert.deepEqual(nested.events, { create: false, unmount: false, destroy: false }); } }; diff --git a/test/runtime/samples/lifecycle-events/main.html b/test/runtime/samples/lifecycle-events/main.html index b39ce292d6..e07f634006 100644 --- a/test/runtime/samples/lifecycle-events/main.html +++ b/test/runtime/samples/lifecycle-events/main.html @@ -1,11 +1,19 @@ -
+