With Liveview, what is best way to download a file to the user's browser?

Sorry, old code follows, this has worked for 10+ years:

jQuery('<iframe>').attr('src', file.url).hide().appendTo(jQuery(document.body))

So let’s adapt it to modern JS / LV interop with this in the body:

window.addEventListener(`phx:download`, (event) => {
  let uri = event.uri;
  let frame = document.createElement("iframe");
  frame.setAttribute("src", response.uri);
  frame.style.visibility = 'hidden';
  frame.style.display = 'none';
  document.body.appendChild(frame);
});

Then from the LiveView you use push_event at the appropriate juncture (name of event, would be download in this case, and it would have the URI) — win/win solution, no redirection (so you keep the LV running), the download proceeds via the same authentication system you have used (as it will go through a known set of Plugs), and the file is downloaded!! Plus this would work nice with things you have to stream (such as via Packmatic etc)

Would recommend reading JavaScript interoperability — Phoenix LiveView v0.17.10 thoroughly.

PS: Could also use a phx-ignore container to hang your iframe in, or just make some space for it in your layout where LV would not touch, all depending on how your app is set up

PS 2: Redirecting away from a LV to something with content-disposition that is not inline probably causes what @ppiechota is seeing. So avoiding full redirection (you can’t get back easily, anyway) or anything that would cause the LV to stop running, would be key here.

12 Likes