HX-Trigger to issue a request using arguments

I want to create a request after a trigger using htmx after a button was clicked with django:

def SomeView(request, var1, var2):
    trigger_data = json.dumps({"dlstart": {"pid": pid, "var1": var1}})
    return HttpResponse("", headers={"HX-Trigger": trigger_data})

I can see in the Network Tab the GET request is working. But now I want to add the two arguments from trigger_data to my hx-get dynamically. I did not find a way in htmx alone to achieve this, so I did a JS workaround (which I would gladly drop in favor of a htmx only solution):

document.body.addEventListener("dlstart", function() {
    const url = `/someURL/${event.detail.pid}/${event.detail.var1}`;
    const filename = "test.png";

    fetch(url)
        .then(response => {
            if (!response.ok) {
                throw new Error('was not ok');
            }
            return response.blob(); 
        })
        .then(blob => {
            const link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);
            link.download = filename; 
            document.body.appendChild(link);
            link.click(); // feels so ugly
            document.body.removeChild(link);
        })
});

I imagine some combination of hx-get and dynamically add the arguments must work too?

It is pretty sneaky to download a server-generated file with htmx-powered requests. But there is an easy workaround that avoids any custom JavaScript at all.

The general idea is to have a view that only offers the download option to the client, like you're doing. The trick then is to simply redirect the request to that view.

In your case, first refactor SomeView:

from django.urls import reverse_lazy

def SomeView(request, var1, var2):
    dl_url = reverse_lazy("some-url", kwargs=dict(pid=pid, var1=var1))
    return HttpResponse(headers={"Hx-Redirect" : dl_url})

This will issue a client redirect to the supplied url. Then in the DLView, return a FileResponse that makes is easy to offer a download option to the client:

from django.http import FileResponse

def DLView(request, pid, var1): 
    # do stuff
    pdf = pdf_create(prod, var1)
    return FileResponse(open(pdf, "rb"), as_attachment=True, filename="test.pdf")

This view should do what your JavaScript is doing by opening a download dialog in the browser. I hope that's what you wish to accomplish.

Note:

It's a convention that function names in Python should be in snake_case, while class names should be in PascalCase. Thus, instead of def DLView..., it should be def dl_view....

Back to Top