Skip to content

Commit 2e78439

Browse files
committed
feat(core events): remove_event_listener - support removal by id and all at once.
Previously registered events can now be removed by a matching id with no element given, like: remove_event_listener(undefined, "my-event-id"); When called with no parameters like "remove_event_listener()" all registered events are removed.
1 parent 7dd9aff commit 2e78439

File tree

2 files changed

+150
-26
lines changed

2 files changed

+150
-26
lines changed

src/core/events.js

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,34 +44,43 @@ const add_event_listener = (el, event_type, id, cb, opts = {}) => {
4444
/**
4545
* Remove an event listener from a DOM element under a unique id.
4646
*
47-
* @param {DOM Node} el - The element to register the event for.
48-
* @param {string} id - A unique id under which the event is registered.
47+
* If an element and id are given, the event listeners for the given element matching the id are removed.
48+
* If an element but no id is given, all event listeners for that element are removed.
49+
* If an id but no element is given, all event listeners for any element matching the id are removed.
50+
* If no element and no id are given, all event listeners are removed.
51+
*
52+
* @param {DOM Node} [el] - The element to register the event for.
53+
* @param {string} [id] - A unique id under which the event is registered.
4954
*
5055
*/
5156
const remove_event_listener = (el, id) => {
52-
if (!el?.removeEventListener) {
53-
return; // nothing to do.
54-
}
55-
const el_events = event_listener_map.get(el);
56-
if (!el_events) {
57-
return;
58-
}
59-
let entries;
60-
if (id) {
61-
// remove event listener with specific id
62-
const entry = el_events.get(id);
63-
entries = entry ? [[id, entry]] : [];
64-
} else {
65-
// remove all event listeners of element
66-
entries = el_events.entries();
67-
}
68-
for (const entry of entries || []) {
69-
el.removeEventListener(entry[1][0], entry[1][1], entry[1][2]);
70-
// Delete entry from event_listener_map
71-
event_listener_map.get(el).delete(entry[0]);
72-
// Delete element from event_listener_map if no more events are registered.
73-
if (!event_listener_map.get(el).size) {
74-
event_listener_map.delete(el);
57+
const els = el ? [el] : event_listener_map.keys();
58+
for (const el of els) {
59+
if (!el?.removeEventListener) {
60+
return; // nothing to do.
61+
}
62+
const el_events = event_listener_map.get(el);
63+
if (!el_events) {
64+
return;
65+
}
66+
let entries;
67+
if (id) {
68+
// remove event listener with specific id
69+
const entry = el_events.get(id);
70+
entries = entry ? [[id, entry]] : [];
71+
} else {
72+
// remove all event listeners of element
73+
entries = el_events.entries();
74+
}
75+
for (const entry of entries || []) {
76+
// Remove event listener
77+
el.removeEventListener(entry[1][0], entry[1][1], entry[1][2]);
78+
// Delete entry from event_listener_map
79+
event_listener_map.get(el).delete(entry[0]);
80+
// Delete element from event_listener_map if no more events are registered.
81+
if (!event_listener_map.get(el).size) {
82+
event_listener_map.delete(el);
83+
}
7584
}
7685
}
7786
};

src/core/events.test.js

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ describe("core.events tests", () => {
169169
expect(cnt2).toBe(2);
170170
expect(cnt3).toBe(2);
171171

172-
// Remove all event handler on el1
172+
// Remove all event handlers on el1
173173
events.remove_event_listener(el1);
174174
expect(event_listener_map.get(el1)).not.toBeDefined();
175175
expect(event_listener_map.size).toBe(1);
@@ -188,6 +188,121 @@ describe("core.events tests", () => {
188188
expect(cnt2).toBe(2);
189189
expect(cnt3).toBe(3);
190190
});
191+
192+
it("Remove all events matching exactly an id from any element.", () => {
193+
const el1 = document.createElement("div");
194+
const el2 = document.createElement("div");
195+
196+
let cnt1 = 0;
197+
let cnt2 = 0;
198+
let cnt3 = 0;
199+
200+
const shared_cb = () => {
201+
cnt1++;
202+
};
203+
204+
// register the event handlers
205+
events.add_event_listener(el1, "test1", "test_event_1", shared_cb);
206+
events.add_event_listener(el1, "test2", "test_event_2", shared_cb);
207+
events.add_event_listener(el1, "test3", "test_event_3", () => cnt2++);
208+
events.add_event_listener(el2, "test4", "test_event_4", () => cnt3++);
209+
210+
expect(event_listener_map.get(el1).get("test_event_1")).toBeDefined();
211+
expect(event_listener_map.get(el1).get("test_event_2")).toBeDefined();
212+
expect(event_listener_map.get(el1).get("test_event_3")).toBeDefined();
213+
expect(event_listener_map.get(el2).get("test_event_4")).toBeDefined();
214+
215+
expect(event_listener_map.size).toBe(2);
216+
217+
el1.dispatchEvent(new Event("test1"));
218+
expect(cnt1).toBe(1);
219+
expect(cnt2).toBe(0);
220+
expect(cnt3).toBe(0);
221+
222+
el1.dispatchEvent(new Event("test1"));
223+
expect(cnt1).toBe(2);
224+
expect(cnt2).toBe(0);
225+
expect(cnt3).toBe(0);
226+
227+
el1.dispatchEvent(new Event("test2"));
228+
expect(cnt1).toBe(3);
229+
expect(cnt2).toBe(0);
230+
expect(cnt3).toBe(0);
231+
232+
el1.dispatchEvent(new Event("test3"));
233+
expect(cnt1).toBe(3);
234+
expect(cnt2).toBe(1);
235+
expect(cnt3).toBe(0);
236+
237+
el2.dispatchEvent(new Event("test4"));
238+
expect(cnt1).toBe(3);
239+
expect(cnt2).toBe(1);
240+
expect(cnt3).toBe(1);
241+
242+
// Remove only test_event_1
243+
events.remove_event_listener(undefined, "test_event_1");
244+
expect(event_listener_map.get(el1).get("test_event_1")).not.toBeDefined();
245+
expect(event_listener_map.get(el1).get("test_event_2")).toBeDefined();
246+
expect(event_listener_map.get(el1).get("test_event_3")).toBeDefined();
247+
expect(event_listener_map.get(el2).get("test_event_4")).toBeDefined();
248+
expect(event_listener_map.size).toBe(2);
249+
250+
// Counter should not increase anymore on event "test1"
251+
el1.dispatchEvent(new Event("test1"));
252+
expect(cnt1).toBe(3);
253+
expect(cnt2).toBe(1);
254+
expect(cnt3).toBe(1);
255+
256+
// Rest should not be affected.
257+
el1.dispatchEvent(new Event("test2"));
258+
el1.dispatchEvent(new Event("test3"));
259+
el2.dispatchEvent(new Event("test4"));
260+
expect(cnt1).toBe(4);
261+
expect(cnt2).toBe(2);
262+
expect(cnt3).toBe(2);
263+
264+
// Remove rest of event handlers on el1
265+
events.remove_event_listener(undefined, "test_event_2");
266+
events.remove_event_listener(undefined, "test_event_3");
267+
expect(event_listener_map.get(el1)).not.toBeDefined();
268+
expect(event_listener_map.size).toBe(1);
269+
270+
// Counter should not increase anymore on el1
271+
el1.dispatchEvent(new Event("test1"));
272+
el1.dispatchEvent(new Event("test2"));
273+
el1.dispatchEvent(new Event("test3"));
274+
expect(cnt1).toBe(4);
275+
expect(cnt2).toBe(2);
276+
expect(cnt3).toBe(2);
277+
278+
// But el2 should still work.
279+
el2.dispatchEvent(new Event("test4"));
280+
expect(cnt1).toBe(4);
281+
expect(cnt2).toBe(2);
282+
expect(cnt3).toBe(3);
283+
});
284+
285+
it("Remove all event listeners at once.", () => {
286+
const el1 = document.createElement("div");
287+
const el2 = document.createElement("div");
288+
289+
// register the event handlers
290+
events.add_event_listener(el1, "test1", "test_event_1", () => {});
291+
events.add_event_listener(el1, "test2", "test_event_2", () => {});
292+
events.add_event_listener(el1, "test3", "test_event_3", () => {});
293+
events.add_event_listener(el2, "test4", "test_event_4", () => {});
294+
295+
expect(event_listener_map.get(el1).get("test_event_1")).toBeDefined();
296+
expect(event_listener_map.get(el1).get("test_event_2")).toBeDefined();
297+
expect(event_listener_map.get(el1).get("test_event_3")).toBeDefined();
298+
expect(event_listener_map.get(el2).get("test_event_4")).toBeDefined();
299+
300+
expect(event_listener_map.size).toBe(2);
301+
302+
// Remove all event listeners
303+
events.remove_event_listener();
304+
expect(event_listener_map.size).toBe(0);
305+
});
191306
});
192307

193308
describe("2 - await pattern initialization", () => {

0 commit comments

Comments
 (0)