The page is very simple, but contains a big table of data in the center. It has a form at the top of the page that allows you to write simple queries for data in the page. When a user types in a SQL Query, the htmx library allows me to reload the table, without fully reloading the page:
What I wanted was:
- if a user typed a SQL query it would be saved in the query string in the URL bar
- if a user sorted the columns the query would be saved into the query string in the URL bar also
This would allow a user to bookmark or copy the url, and then send it to some other user, and they could get the same data.
The htmx library provides the ability for the server-side to send back a URL to be pushed into the browser: https://htmx.org/reference/#response_headers
The way this works, is that you set the
HX-Push response header, and the URL in that header will be pushed to the browser’s history+url bar.
One complication was that the sorting of the table is done client-side, but the querying is done server-side. This means that the query parameters get all mixed together when the request comes to the backend, so what I needed to do on the Flask side is split up the
request.referrer (the URL the request came from) as well as the
request.args (the query params of the htmx partial request).
Enough talk, lets see the code:
def server_table(db_session): # these are the parameters I care about in the htmx triggered request sqlquery_query = request.args.get('sqlquery') showdecom_query = request.args.get('showdecom') if request.referrer: # the referrer is the current top-level URL # Build a new URL to push to history for htmx referrer_url = list(urllib.parse.urlparse(request.referrer)) # parse the query_string_list (qsl) query_dict = dict(urllib.parse.parse_qsl(referrer_url)) # Remove the items from the referrer that should only come from the htmx triggered request: query_dict.pop('showdecom', None) query_dict.pop('sqlquery', None) filtered_args = filter(lambda item: bool(item), request.args.items()) # we only want query items that have a value query_dict.update(filtered_args) # add them to the to the new query we are building referrer_url = urllib.parse.urlencode(query_dict) new_history_url = urllib.parse.urlunparse(referrer_url) else: new_history_url = None response = flask.Response(generate_server_table(db_session)) if new_history_url: # if we built a new URL, send it in the response header response.headers["HX-Push"] = new_history_url return response