Categories
Programming

Saving query parameters into the browser history, using Flask + HTMX

I’ve recently been using the htmx (https://htmx.org/) javascript library to make some simple Flask web applications I have made a bit more dynamic.

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:

screenshot of the page containing the table and query at the top

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[4]))

        # 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[1]), 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[4] = 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

Leave a Reply

Your email address will not be published.