handle event listener registration before mount; handle unregister

pull/8457/head
Simon Holthausen 3 years ago
parent 149c10010b
commit 96e97682e0

@ -152,6 +152,8 @@ if (typeof HTMLElement === 'function') {
private $$data = {}; private $$data = {};
private $$reflecting = false; private $$reflecting = false;
private $$props_definition: Record<string, CustomElementPropDefinition> = {}; private $$props_definition: Record<string, CustomElementPropDefinition> = {};
private $$listeners: Record<string, Function[]> = {};
private $$listener_unsubscribe_fns = new Map<Function, Function>();
constructor( constructor(
private $$componentCtor: ComponentType, private $$componentCtor: ComponentType,
@ -165,10 +167,26 @@ if (typeof HTMLElement === 'function') {
// We can't determine upfront if the event is a custom event or not, so we have to // We can't determine upfront if the event is a custom event or not, so we have to
// listen to both. If someone uses a custom event with the same name as a regular // listen to both. If someone uses a custom event with the same name as a regular
// browser event, this fires twice - we can't avoid that. // browser event, this fires twice - we can't avoid that.
this.$$component!.$on(type, listener); this.$$listeners[type] = this.$$listeners[type] || [];
this.$$listeners[type].push(listener);
if (this.$$component) {
const unsub = this.$$component!.$on(type, listener);
this.$$listener_unsubscribe_fns.set(listener, unsub);
}
super.addEventListener(type, listener, options); super.addEventListener(type, listener, options);
} }
removeEventListener(type: string, listener: any, options?: any): void {
super.removeEventListener(type, listener, options);
if (this.$$component) {
const unsub = this.$$listener_unsubscribe_fns.get(listener);
if (unsub) {
unsub();
this.$$listener_unsubscribe_fns.delete(listener);
}
}
}
async connectedCallback() { async connectedCallback() {
this.$$connected = true; this.$$connected = true;
if (!this.$$component) { if (!this.$$component) {
@ -228,6 +246,14 @@ if (typeof HTMLElement === 'function') {
} }
} }
}); });
for (const type in this.$$listeners) {
for (const listener of this.$$listeners[type]) {
const unsub = this.$$component!.$on(type, listener);
this.$$listener_unsubscribe_fns.set(listener, unsub);
}
}
this.$$listeners = {};
} }
} }

@ -4,10 +4,20 @@ import './main.svelte';
export default async function (target) { export default async function (target) {
target.innerHTML = '<custom-element></custom-element>'; target.innerHTML = '<custom-element></custom-element>';
await tick();
const el = target.querySelector('custom-element'); const el = target.querySelector('custom-element');
const events = []; const events = [];
const custom_before = () => {
events.push('before');
};
const click_before = () => {
events.push('click_before');
};
el.addEventListener('custom', custom_before);
el.addEventListener('click', click_before);
await tick();
el.addEventListener('custom', e => { el.addEventListener('custom', e => {
events.push(e.detail); events.push(e.detail);
}); });
@ -16,5 +26,10 @@ export default async function (target) {
}); });
el.shadowRoot.querySelector('button').click(); el.shadowRoot.querySelector('button').click();
assert.deepEqual(events, ['foo', 'click']); assert.deepEqual(events, ['before', 'foo', 'click_before', 'click']);
el.removeEventListener('custom', custom_before);
el.removeEventListener('click', click_before);
el.shadowRoot.querySelector('button').click();
assert.deepEqual(events, ['before', 'foo', 'click_before', 'click', 'foo', 'click']);
} }

Loading…
Cancel
Save