fix(pagination): update URL on pagination and search

This commit addresses two issues with pagination and search:

1.  **Pagination URL Update**: Added `hx-push-url` to pagination buttons in the customer, order, and invoice list templates. This ensures the browser URL and history are updated when navigating pages via HTMX. The query parameters for `status` and `search` are now conditionally included, preventing empty parameters (e.g., `&status=`) in the URL.

2.  **Search URL Reset**: Updated the `CustomerList` handler to send the `HX-Push-Url` header when performing a search via HTMX. This ensures that when a search is executed (or cleared), the URL correctly reflects the new state (reseting the page to 1), fixing a mismatch where the URL could show page 4 while the content was reset to page 1.
This commit is contained in:
Victor Broman 2026-02-07 10:19:32 +01:00
parent aa3b63095c
commit 2dfe0a48ea
4 changed files with 20 additions and 6 deletions

@ -1,6 +1,7 @@
package handlers
import (
"fmt"
"net/http"
"strconv"
@ -39,6 +40,13 @@ func (h *Handler) CustomerList(w http.ResponseWriter, r *http.Request) {
// HTMX partial for search
if r.Header.Get("HX-Request") == "true" && r.URL.Query().Get("partial") == "true" {
// Construct clean URL for history
u := fmt.Sprintf("/customers?page=%d", page)
if search != "" {
u += "&search=" + search
}
w.Header().Set("HX-Push-Url", u)
h.renderPartial(w, "customers/list.html", "customer-table", data)
return
}

@ -72,7 +72,8 @@
<nav class="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
{{if .HasPrev}}
<button
hx-get="/customers?page={{.PrevPage}}&search={{.Search}}&partial=true"
hx-get="/customers?page={{.PrevPage}}{{if .Search}}&search={{.Search}}{{end}}&partial=true"
hx-push-url="/customers?page={{.PrevPage}}{{if .Search}}&search={{.Search}}{{end}}"
hx-target="#customer-table"
class="relative inline-flex items-center rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
<span class="sr-only">Previous</span>
@ -83,7 +84,8 @@
{{end}}
{{if .HasNext}}
<button
hx-get="/customers?page={{.NextPage}}&search={{.Search}}&partial=true"
hx-get="/customers?page={{.NextPage}}{{if .Search}}&search={{.Search}}{{end}}&partial=true"
hx-push-url="/customers?page={{.NextPage}}{{if .Search}}&search={{.Search}}{{end}}"
hx-target="#customer-table"
class="relative inline-flex items-center rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
<span class="sr-only">Next</span>

@ -76,7 +76,8 @@
<nav class="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
{{if .HasPrev}}
<button
hx-get="/invoices?page={{.PrevPage}}&status={{.FilterStatus}}&partial=true"
hx-get="/invoices?page={{.PrevPage}}{{if .FilterStatus}}&status={{.FilterStatus}}{{end}}&partial=true"
hx-push-url="/invoices?page={{.PrevPage}}{{if .FilterStatus}}&status={{.FilterStatus}}{{end}}"
hx-target="#invoice-table"
class="relative inline-flex items-center rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
<span class="sr-only">Previous</span>
@ -87,7 +88,8 @@
{{end}}
{{if .HasNext}}
<button
hx-get="/invoices?page={{.NextPage}}&status={{.FilterStatus}}&partial=true"
hx-get="/invoices?page={{.NextPage}}{{if .FilterStatus}}&status={{.FilterStatus}}{{end}}&partial=true"
hx-push-url="/invoices?page={{.NextPage}}{{if .FilterStatus}}&status={{.FilterStatus}}{{end}}"
hx-target="#invoice-table"
class="relative inline-flex items-center rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
<span class="sr-only">Next</span>

@ -78,7 +78,8 @@
<nav class="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
{{if .HasPrev}}
<button
hx-get="/orders?page={{.PrevPage}}&status={{.FilterStatus}}&partial=true"
hx-get="/orders?page={{.PrevPage}}{{if .FilterStatus}}&status={{.FilterStatus}}{{end}}&partial=true"
hx-push-url="/orders?page={{.PrevPage}}{{if .FilterStatus}}&status={{.FilterStatus}}{{end}}"
hx-target="#order-table"
class="relative inline-flex items-center rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
<span class="sr-only">Previous</span>
@ -89,7 +90,8 @@
{{end}}
{{if .HasNext}}
<button
hx-get="/orders?page={{.NextPage}}&status={{.FilterStatus}}&partial=true"
hx-get="/orders?page={{.NextPage}}{{if .FilterStatus}}&status={{.FilterStatus}}{{end}}&partial=true"
hx-push-url="/orders?page={{.NextPage}}{{if .FilterStatus}}&status={{.FilterStatus}}{{end}}"
hx-target="#order-table"
class="relative inline-flex items-center rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
<span class="sr-only">Next</span>