Skip to content

Commit 976add6

Browse files
committed
[LiveComponent] Fix live component rendering when loaded from bfcache
1 parent f5bc06f commit 976add6

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

src/LiveComponent/assets/dist/live_controller.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,9 +1246,13 @@ class default_1 extends Controller {
12461246
this.markAsWindowUnloaded = () => {
12471247
this.isWindowUnloaded = true;
12481248
};
1249+
this.markAsWindowNotUnloaded = () => {
1250+
this.isWindowUnloaded = false;
1251+
};
12491252
}
12501253
initialize() {
12511254
this.markAsWindowUnloaded = this.markAsWindowUnloaded.bind(this);
1255+
this.markAsWindowNotUnloaded = this.markAsWindowNotUnloaded.bind(this);
12521256
this.handleUpdateModelEvent = this.handleUpdateModelEvent.bind(this);
12531257
this.handleInputEvent = this.handleInputEvent.bind(this);
12541258
this.handleChangeEvent = this.handleChangeEvent.bind(this);
@@ -1266,7 +1270,8 @@ class default_1 extends Controller {
12661270
throw new Error('Invalid Element Type');
12671271
}
12681272
this._initiatePolling();
1269-
window.addEventListener('beforeunload', this.markAsWindowUnloaded);
1273+
window.addEventListener('pagehide', this.markAsWindowUnloaded);
1274+
window.addEventListener('pageshow', this.markAsWindowNotUnloaded);
12701275
this._startAttributesMutationObserver();
12711276
this.element.addEventListener('live:update-model', this.handleUpdateModelEvent);
12721277
this.element.addEventListener('input', this.handleInputEvent);
@@ -1277,7 +1282,8 @@ class default_1 extends Controller {
12771282
disconnect() {
12781283
this._stopAllPolling();
12791284
__classPrivateFieldGet(this, _instances, "m", _clearRequestDebounceTimeout).call(this);
1280-
window.removeEventListener('beforeunload', this.markAsWindowUnloaded);
1285+
window.removeEventListener('pagehide', this.markAsWindowUnloaded);
1286+
window.removeEventListener('pageshow', this.markAsWindowNotUnloaded);
12811287
this.element.removeEventListener('live:update-model', this.handleUpdateModelEvent);
12821288
this.element.removeEventListener('input', this.handleInputEvent);
12831289
this.element.removeEventListener('change', this.handleChangeEvent);

src/LiveComponent/assets/src/live_controller.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export default class extends Controller implements LiveController {
8787

8888
initialize() {
8989
this.markAsWindowUnloaded = this.markAsWindowUnloaded.bind(this);
90+
this.markAsWindowNotUnloaded = this.markAsWindowNotUnloaded.bind(this);
9091
this.handleUpdateModelEvent = this.handleUpdateModelEvent.bind(this);
9192
this.handleInputEvent = this.handleInputEvent.bind(this);
9293
this.handleChangeEvent = this.handleChangeEvent.bind(this);
@@ -111,7 +112,8 @@ export default class extends Controller implements LiveController {
111112

112113
this._initiatePolling();
113114

114-
window.addEventListener('beforeunload', this.markAsWindowUnloaded);
115+
window.addEventListener('pagehide', this.markAsWindowUnloaded);
116+
window.addEventListener('pageshow', this.markAsWindowNotUnloaded);
115117
this._startAttributesMutationObserver();
116118
this.element.addEventListener('live:update-model', this.handleUpdateModelEvent);
117119
this.element.addEventListener('input', this.handleInputEvent);
@@ -125,7 +127,8 @@ export default class extends Controller implements LiveController {
125127
this._stopAllPolling();
126128
this.#clearRequestDebounceTimeout();
127129

128-
window.removeEventListener('beforeunload', this.markAsWindowUnloaded);
130+
window.removeEventListener('pagehide', this.markAsWindowUnloaded);
131+
window.removeEventListener('pageshow', this.markAsWindowNotUnloaded);
129132
this.element.removeEventListener('live:update-model', this.handleUpdateModelEvent);
130133
this.element.removeEventListener('input', this.handleInputEvent);
131134
this.element.removeEventListener('change', this.handleChangeEvent);
@@ -799,6 +802,10 @@ export default class extends Controller implements LiveController {
799802
this.isWindowUnloaded = true;
800803
};
801804

805+
markAsWindowNotUnloaded = () => {
806+
this.isWindowUnloaded = false;
807+
};
808+
802809
handleConnectedControllerEvent(event: any) {
803810
if (event.target === this.element) {
804811
return;

src/LiveComponent/assets/test/controller/render.test.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ describe('LiveController rendering Tests', () => {
232232

233233
test.controller.$render();
234234
// imitate navigating away
235-
fireEvent(window, createEvent('beforeunload', window));
235+
fireEvent(window, createEvent('pagehide', window));
236236

237237
// wait for the fetch to finish
238238
await fetchMock.flush();
@@ -241,6 +241,37 @@ describe('LiveController rendering Tests', () => {
241241
expect(test.element).not.toHaveTextContent('Hello');
242242
});
243243

244+
it('renders if the page is navigating away and back', async () => {
245+
const test = await createTest({greeting: 'aloha!'}, (data: any) => `
246+
<div ${initComponent(data)}>${data.greeting}</div>
247+
`);
248+
249+
test.expectsAjaxCall('get')
250+
.expectSentData(test.initialData)
251+
.serverWillChangeData((data) => {
252+
data.greeting = 'Hello';
253+
})
254+
.delayResponse(100)
255+
.init();
256+
257+
test.controller.$render();
258+
// imitate navigating away
259+
fireEvent(window, createEvent('pagehide', window));
260+
// wait for the fetch to finish
261+
await fetchMock.flush();
262+
263+
expect(test.element).toHaveTextContent('aloha!')
264+
265+
// navigate back
266+
fireEvent(window, createEvent('pageshow', window));
267+
test.controller.$render();
268+
// wait for the fetch to finish
269+
await fetchMock.flush();
270+
271+
// the re-render should have happened
272+
expect(test.element).toHaveTextContent('Hello');
273+
});
274+
244275
it('waits for the previous request to finish & batches changes', async () => {
245276
const test = await createTest({ title: 'greetings', contents: '' }, (data: any) => `
246277
<div ${initComponent(data, { debounce: 1 })}>

0 commit comments

Comments
 (0)