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

hx-history not working on partial content #3165

Open
mrinc opened this issue Feb 2, 2025 · 4 comments
Open

hx-history not working on partial content #3165

mrinc opened this issue Feb 2, 2025 · 4 comments

Comments

@mrinc
Copy link

mrinc commented Feb 2, 2025

When using hx-push-url with partial content, pressing the back button does not actually work.

From looking at the code, it seems that it's related to the context being on the body.
In the case where we do not actually control the body, the history aspect fails completely.
I have been digging and it seems there is a case where HTMX is loaded dynamically on page load where the DOMContentLoaded is never triggered.

If I instead push the events for the ready function into an array, and then manually call those functions, everything works perfectly.

htmx/src/htmx.js

Lines 4994 to 5014 in 10e8656

var isReady = false
getDocument().addEventListener('DOMContentLoaded', function() {
isReady = true
})
/**
* Execute a function now if DOMContentLoaded has fired, otherwise listen for it.
*
* This function uses isReady because there is no reliable way to ask the browser whether
* the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded
* firing and readystate=complete.
*/
function ready(fn) {
// Checking readyState here is a failsafe in case the htmx script tag entered the DOM by
// some means other than the initial page load.
if (isReady || getDocument().readyState === 'complete') {
fn()
} else {
getDocument().addEventListener('DOMContentLoaded', fn)
}
}

So, we need to find a way to reliably trigger that event... I'll keep looking and update this accordingly.

@mrinc
Copy link
Author

mrinc commented Feb 2, 2025

I have also noticed a condition that could be problematic.

localStorage vs sessionStorage.
Any reason why we don't use sessionStorage for history state? (didn't find any discussions about it from a quick gander)

mrinc added a commit to mrinc/htmx that referenced this issue Feb 2, 2025
By using a a temporary list of functions instead of adding the functions to the DOMContentLoaded, we can mitigate the issues where the event is sometimes not fired.
Also, using the window.onload as a backup to trigger the functions.
mrinc added a commit to mrinc/htmx that referenced this issue Feb 2, 2025
Fixes case where htmx is loaded async and DOMContentLoaded is never fired.
@mrinc mrinc mentioned this issue Feb 2, 2025
4 tasks
@MichaelWest22
Copy link
Contributor

Yeah there is a good argument to be made that htmx should use session storage instead of local.

Are you linking to htmx in a head tag properly when you have this issue? I've seen similar issues in #2865 where the htmx script tag is not loaded correctly in the head tag. Htmx has to load and stay loaded all the time for history navigation to work as expected. Pushing back if historyCacheSize is not zero should just swap the body contents but retain the head scripts like htmx in place. I only got it to work properly when htmx was loaded in the body by testing modifying it to store it's saved history url value into sessionStorage from memory.

@mrinc
Copy link
Author

mrinc commented Feb 3, 2025

No no, it's async.
As in ...

const elem = document.createElement('script');
document.head.appendChild(elem);

async (basically script load with a script over in head/body - ie ... we do not have control of the page)

It is loaded during page load basically.

The problem is (see my bugfix) is the ready function never gets called when doing this.
The navigation fails completely even with disabling history etc - doesn't matter.
If you try press back, it just does nothing - history fails completely.

When looking into the code, the history/forward/backward functions are setup during the DOMContentLoaded - but since that event never fires in this case, it never sets the above up - thus a failure mode.
So, I added window.onload as a additional check - so either DOMContentLoaded or window.onload (whichever is first) allows the ready function to work and setup htmx properly.

@mrinc
Copy link
Author

mrinc commented Feb 3, 2025

For the referenced issue - it is possible that it's having a similar effect since it is at the end of the body instead.
That should work so possible related fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants