htmx icon indicating copy to clipboard operation
htmx copied to clipboard

Include query parameters when using custom `hx-push-url` value

Open JonasR opened this issue 1 year ago • 5 comments

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.

JonasR avatar Jan 06 '24 12:01 JonasR

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!

Telroshan avatar Jan 07 '24 16:01 Telroshan

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>

y2kbugger avatar Jan 18 '24 19:01 y2kbugger

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.

ericvsmith avatar Feb 14 '24 23:02 ericvsmith

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/searchwhich 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

aguacatedan avatar Feb 28 '24 01:02 aguacatedan

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>

aguacatedan avatar Feb 28 '24 01:02 aguacatedan