Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handles firing closeOnClick before another listener #10926

Merged
merged 9 commits into from
Aug 12, 2021
6 changes: 6 additions & 0 deletions src/util/evented.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ export class Evented {

// make sure adding or removing listeners inside other listeners won't cause an infinite loop
const listeners = this._listeners && this._listeners[type] ? this._listeners[type].slice() : [];

// Check if onClose is an event listener and move to front of list to fire first
if (listeners.length > 1 && listeners[1].name === "bound _onClose") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may work for this specific use case, but this solution is brittle, with possible cases where it breaks and it's very hard to debug — for example, what if a user puts multiple click listeners on a popup? Then _onClose will not be the second, but later in the array. What if a user adds a listener with the same name? What if a different class in GL JS (not popup) uses the same method name (_onClose) and the execution order is swapped unexpectedly?

I think we should find a solution that's more explicit and can't produce unexpected side effects — e.g. firing a preclick event before click here and then subscribing to it for Popup closeOnClick. This is how Leaflet handles it as seen here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for the feedback! Yes I wasn't confident on this initial approach. I appreciate sending over the resources and example from leaflet. I implemented a preclick that works manually with the debug file but is breaking some of the unit tests in test/unit/ui/map_events.test.js that I'm looking into now.

listeners.unshift(listeners.splice(1, 1)[0]);
}

for (const listener of listeners) {
listener.call(this, event);
}
Expand Down