htmx
htmx copied to clipboard
Include query parameters when using custom `hx-push-url` value
I'm trying to use a custom value for hx-push-url
(i.e. not hx-push-url="true"
) and still retain any query parameters (from hx-get
).
Consider the following example:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get("/debug", response_class=HTMLResponse)
def debg(number: int | None = None):
if number:
return f"<p>Selected {number}</p>"
return HTMLResponse(
"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HTMX #653</title>
<script
src="https://unpkg.com/[email protected]"
integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC"
crossorigin="anonymous">
</script>
</head>
<body>
<select id="select-number" name="number" hx-get="/debug" hx-push-url="/debug2" hx-target="#target">
<option value="1">1</option>
<option value="2">2</option>
</select>
<div id="target">
</div>
</body>
</html>
"""
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app)
When browsing to /debug
and selecting 2
in the dropdown it triggers a "GET /debug?number=2
as expected. However, the URL pushed is just /debug2
while I would want it to be /debug2?number=2
. Is that possible?
I have previously replied to the related #653 and don't seem to be the only one interested. There, the answer by @1cg implies this should work, however, as @dcr8898 pointed out the current code does not look like it's supposed to.
Hey, as far as I know this is currently not possible with the hx-push-url
attribute, but you could achieve what you want here using the HX-Push-Url
response header
Hope it helps!
This would be a useful option for any type of form where the search results url doesn't match the original pages url.
<label class="form-label" for="component_name">Part Number:</label>
<input class="form-control"
value="{{ component_name }}"
type="search"
name="component_name"
placeholder="Enter a Part Number"
hx-get="parts/search"
hx-target="#search-results"
hx-trigger="input changed delay: 500ms, search, load"
hx-push-url="parts"
/>
<div class="mt-3" id="search-results"></div>
Yes, this would indeed be handy. Basically I want to stay on a page (that is, the page itself isn't being refreshed), but whenever any hx-get
is triggered, push the url to the base base followed by query params. That way I could arrange so that if the user returned to the pushed url (base page plus those query params), they'd see they same thing as if they'd selected the base page then manually triggered the hx-get
. I hope that makes sense. I think it would be as simple as a way to say that the specified hx-push-url
(which I would set to the base page) is followed by hx-include variables. Maybe some special hx-include prefix, like hx-include="push:this"
, or a new hx-include-push="this"
. Whatever values would be allowed with hx-include
would be allowed with hx-include-push
.
I'd love to see this implemented as well. My use case is for AEM - here's some context:
consider a page: www.site.com/search
which includes these components:
- hero
- promo
- search-results
When you navigate to that page, all of those components are rendered in the back end. But you can do a request to the search-results component directly:
www.site.com/search/jcr:content/search-results.html
and this will render only the markup of that component. HTMX is perfect for this. However, this limitation of hx-push-url doesn't let me update the page URL like I want:
-
hx-push-url="true"
will update the location history with all the parameters but the wrong path:www.site.com/search/jcr:content/search-results.html?p=foobar
, -
hx-push-url="/search"
will update the location history with the desired path but without the query parameters
I'll write an extension for now, but i'd love to see this integrated into the library if possible
I resorted to writing an extension for now:
htmx.defineExtension('push-url-w-params', {
onEvent : function(name, e) {
if (name === "htmx:configRequest") {
const path = e.target.getAttribute('data-push-url')
const params = new URLSearchParams(e.detail.parameters).toString()
const url = `${window.location.origin}${path}?${params}`
window.history.pushState({}, '', url);
}
}
})
then use it like this:
<div hx-get="..."
hx-trigger="..."
hx-ext="push-url-w-params"
data-push-url="/foo/bar.html">
(...)
</div>