Should this be a handle_event or an <a> tag?

I have an app with a date filter – a select dropdown that updates the :range assign on change.

Next to it there is a “Download CSV” button that hits a controller that calls a function that downloads a CSV with data coming from the range in the date filter.

I’ve tried getting the functionality of the Download CSV button working two different ways and neither works exactly right.

The first way was with a button component I built, like so:

<.button
label="Downlaod CSV"
link_type="a"
to={Routes.feedback_path(PbWeb.Endpoint, :csv_download, range: @range)}
/>

The problem I’m running into is that the range value is not being updated when I update my select, even though the range is successfully being updated in the assigns.

The second way was with a binding on the button, like the following:

<a phx-click="download_csv">
Download CSV
</a>
def handle_event("download_csv", _, socket) do 

socket =
	push_redirect(socket,
	to:
	"/feedback/csv_download?range=#{socket.assigns.range}"
	)

{:noreply, socket}

end

This technically works, except that because it is a live redirect that is going to a csv stream, it kills the socket and you’re able to interact with the page but nothing actually happens, plus there’s a big infinitely loading bar at the top of the browser, and I get this error in the network: `error: unauthorized live_redirect. Falling back to page request - Object { reason: “unauthorized” } reason: “unauthorized” : Object { … }"``

So basically I need to either (A) have the params update when the assigns update, or (B) have a redirect like an <a> tag would but in the handle_event.

Any help would be appreciated!

How big is your data? If your data is smaller than a few MB, you can use this approach:

  • stream it in the background to the javascript side using push_event. The javascript side can catch it and store in a byte array.
  • Once the download is complete, render a <a> tag to point to a blob url backed by the byte array in the javascript side
  • Then the user can choose to click the link and save the file. The “download” will be instantaneous because the content is already local.

This is how I implement attachment downloading in GitHub - derek-zhou/liv: Web mail of your own It is not the best use of the available bandwidth but you never leave your liveview, and you don’t need a second channel.

I am embarrassed to admit what this problem was, but the issue was that my <.form> was wrapped in a phx-update="ignore" and that’s why the assigns was not updating in my button.

Removed that and things work as expected. homer_bush

2 Likes