Fix event listener accumulation on repeated init() calls #778
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
🛠 Fix: Prevent Event Listener Accumulation on Section Navigation
Impact
Phoenix uses a root-level
EventDisplayServicethat stays alive while navigating between sections (ATLAS, CMS, LHCb, TrackML, etc.).Each section calls
eventDisplay.init()on navigation, which caused global event listeners to be re-registered every time without removing the old ones.Over multiple navigations, this led to:
resize,keydown, andOrbitControlslistenersThis issue directly affects normal Phoenix usage, especially when users compare multiple detectors in a single session.
Steps to Reproduce
Open Phoenix in Chrome and open DevTools → Console
Navigate through several sections:
After each navigation, run:
Before the fix:
The listener count increases on every navigation.
Expected behavior:
Listener count should remain constant.
Root Cause
EventDisplayServiceis a singleton (providedIn: 'root')init()is called on every section navigationinit()assumes a fresh instance and registers global listenersThis resulted in unbounded listener accumulation over time.
Fix
The fix introduces explicit lifecycle cleanup and makes re-initialization safe:
EventDisplaynow cleans up before re-initializingMinimal example:
This pattern is applied consistently across renderer, controls, and keyboard handlers.
Result
Notes