Skip to content

Commit 20be759

Browse files
authored
don't leak ref event listeners (#3787)
Relates to: #3784
1 parent fa9af28 commit 20be759

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

assets/js/phoenix_live_view/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const PHX_LINK_STATE = "data-phx-link-state";
2020
export const PHX_REF_LOADING = "data-phx-ref-loading";
2121
export const PHX_REF_SRC = "data-phx-ref-src";
2222
export const PHX_REF_LOCK = "data-phx-ref-lock";
23+
export const PHX_PENDING_REFS = "phx-pending-refs";
2324
export const PHX_TRACK_UPLOADS = "track-uploads";
2425
export const PHX_UPLOAD_REF = "data-phx-upload-ref";
2526
export const PHX_PREFLIGHTED_REFS = "data-phx-preflighted-refs";

assets/js/phoenix_live_view/element_ref.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
PHX_REF_LOADING,
33
PHX_REF_LOCK,
44
PHX_REF_SRC,
5+
PHX_PENDING_REFS,
56
PHX_EVENT_CLASSES,
67
PHX_DISABLED,
78
PHX_READONLY,
@@ -42,6 +43,12 @@ export default class ElementRef {
4243

4344
maybeUndo(ref, phxEvent, eachCloneCallback) {
4445
if (!this.isWithin(ref)) {
46+
// we cannot undo the lock / loading now, as there is a newer one already set;
47+
// we need to store the original ref we tried to send the undo event later
48+
DOM.updatePrivate(this.el, PHX_PENDING_REFS, [], (pendingRefs) => {
49+
pendingRefs.push(ref);
50+
return pendingRefs;
51+
});
4552
return;
4653
}
4754

@@ -51,6 +58,29 @@ export default class ElementRef {
5158
// undo loading states
5259
this.undoLoading(ref, phxEvent);
5360

61+
// ensure undo events are fired for pending refs that
62+
// are resolved by the current ref, otherwise we'd leak event listeners
63+
DOM.updatePrivate(this.el, PHX_PENDING_REFS, [], (pendingRefs) => {
64+
return pendingRefs.filter((pendingRef) => {
65+
let opts = {
66+
detail: { ref: pendingRef, event: phxEvent },
67+
bubbles: true,
68+
cancelable: false,
69+
};
70+
if (this.loadingRef && this.loadingRef > pendingRef) {
71+
this.el.dispatchEvent(
72+
new CustomEvent(`phx:undo-loading:${pendingRef}`, opts),
73+
);
74+
}
75+
if (this.lockRef && this.lockRef > pendingRef) {
76+
this.el.dispatchEvent(
77+
new CustomEvent(`phx:undo-lock:${pendingRef}`, opts),
78+
);
79+
}
80+
return pendingRef > ref;
81+
});
82+
});
83+
5484
// clean up if fully resolved
5585
if (this.isFullyResolvedBy(ref)) {
5686
this.el.removeAttribute(PHX_REF_SRC);

0 commit comments

Comments
 (0)