How do I trigger a file download when a button is clicked?
For testing sake, when making a GET request using <Link href="/api/generate-pdf"/>
it works fine and the pdf file is saved. With the button the api is hit but the download is not triggered.
My button rendered in a Nextjs 13 Client Component:
function generatePdf() {
fetch("/api/generate-pdf", {
method: "POST",
headers: {
"Content-type": "application/pdf",
},
body: JSON.stringify(store),
})
}
<Button onClick={generatePdf} type="button">
Generate PDF
</Button>
API Route Handler:
export async function POST(request: Request) {
console.log("/api/generate-pdf POST Request")
try {
// ...
// generate the pdf file
const generatedPdf = doc.output("blob")
const filename = "pac.pdf"
const res = new Response(generatedPdf, {
status: 200,
headers: {
"Content-Type": "application/pdf",
"content-disposition": `attachment; filename="${filename}"`,
},
})
return res
} catch (error) {
console.log(error)
return NextResponse.json("Internal Error", { status: 500 })
}
}
2
Answers
The issue you’re probably encountering is due to the fact that the fetch API does not handle file downloads in the same way a direct link does. When you click the button, the
fetch
API makes the request and receives the response, but it’s not triggering the file download that a direct link would.To solve this, you can modify your
generatePdf
function to create a new Blob object from the response and then create a new object URL for that Blob. One way which I can think of after that is you can programmatically click a hidden anchor element that points to this object URL to trigger the file download(using a’s download attribute) something like below:When you’re making an AJAX request to download a file (like using the fetch API in your case), the browser doesn’t automatically know how to handle the file once it receives the data. To trigger a download, you’ll need to do some extra handling on the client side once the file data is received.
Hear’s a breakdown of the additional steps:
1.After getting the response, you transform it into a blob.
2.Create a URL from that blob using URL.createObjectURL().
3.Create a hidden anchor () element, set the href to the blob URL, and programmatically click it. This causes the browser to download the file.
4.Remove the anchor element after triggering the download.
Also, please note that the Content-Type header in your fetch method should be "application/json" since you’re sending JSON data. Make sure your server can handle that type of content when receiving the request.