diff --git a/src/events.test.ts b/src/events.test.ts index 60e7c355f..1d335aac5 100644 --- a/src/events.test.ts +++ b/src/events.test.ts @@ -57,6 +57,42 @@ describe("EventDispatcher", () => { expect(calls).toEqual(["first", "second", "first"]); }); + it("defers listeners added by the singular handler until the next dispatch", () => { + const dispatcher = new EventDispatcher(); + const calls: string[] = []; + const listener = () => calls.push("listener"); + + dispatcher.setHandler("change", () => { + calls.push("handler"); + dispatcher.addEventListener("change", listener); + dispatcher.setHandler("change", undefined); + }); + + dispatcher.dispatch("change", { value: 1 }); + expect(calls).toEqual(["handler"]); + + dispatcher.dispatch("change", { value: 2 }); + expect(calls).toEqual(["handler", "listener"]); + }); + + it("keeps listeners removed by the singular handler in the current dispatch", () => { + const dispatcher = new EventDispatcher(); + const calls: string[] = []; + const listener = () => calls.push("listener"); + + dispatcher.addEventListener("change", listener); + dispatcher.setHandler("change", () => { + calls.push("handler"); + dispatcher.removeEventListener("change", listener); + }); + + dispatcher.dispatch("change", { value: 1 }); + expect(calls).toEqual(["handler", "listener"]); + + dispatcher.dispatch("change", { value: 2 }); + expect(calls).toEqual(["handler", "listener", "handler"]); + }); + it("warns only when one singular handler replaces another", () => { const dispatcher = new EventDispatcher(); const warn = spyOn(console, "warn").mockImplementation(() => {}); diff --git a/src/events.ts b/src/events.ts index aa2e8623a..fe089d8cc 100644 --- a/src/events.ts +++ b/src/events.ts @@ -72,8 +72,9 @@ export class EventDispatcher> { | EventSlot | undefined; if (!slot) return; + const listeners = [...slot.listeners]; slot.onHandler?.(params); - for (const l of [...slot.listeners]) l(params); + for (const l of listeners) l(params); } private _ensureEventSlot(