DEV Community

Bruno Oliveira
Bruno Oliveira

Posted on

Flask series part 4 - Enabling users to download recipe details as PDF

Introduction

In order to extend the capabilities of our Flask app, we will add a simple button to download a recipe details and instructions as PDF.

There are multiple ways we can approach this small feature, but, the simplest one is to use the capabilities of JS and the browser to invoke system specific calls to display a dialog box that allows one to print the current page as a PDF.

The end result will look like this:

download

Notice the download, link-styled button on the right of the title of the recipe.

When clicking it, the user will be presented a native system dialog containing the current window ready to be printed, and, then, we can save it as a PDF.

Let's see how to implement this.

Implementing the native browser print functionality

To know what to print to a PDF, it is first necessary to know how to select the whole page as HTML and then the browser will be able to handle the printing of that content to file.

In JS, there is an object, called the windowobject.

The window object is supported by all browsers. It represents the browser's window.

All global JavaScript objects, functions, and variables automatically become members of the window object.

More importantly, the document object (of the HTML DOM) is a property of the window object as well, which means that the window object knows about the HTML we have in our application.

It contains a very useful method: print().

As the name indicates, it prints the current window, and, the way it does it is by opening the native browser print dialog where the user can then choose the option to save to PDF.

Obviously, this approach is quite simplistic and it goes straight to the point. It has some limitations, since the user can have some specific printer settings configured and some additional manual tweaking will be needed on such cases. But, it also has some advantages:

  1. No external library required;

  2. We can print only selected parts of the body via customization with CSS;

  3. No JS issues or lock-in to specific APIs;

  4. Core functionality of the browser;

  5. Supported by all major browsers;

Taking this into account, it's a wise choice to use this method to enrich our app's functionality and move forward to more interesting things.

Configuring the Jinja template and JS

To configure the Jinja template, we simply need to add the element we want, in front of the recipe title:

<div>
    <p id="recipeTitle">
        {{ recipe_id[0]['title'] }} <button id="downloadBtn" class='btn btn-link' onclick="getPdf()">
    <span class='glyphicon glyphicon-download'></span></button>
    </p>
</div>

So the top element we saw above, consists of the title of the recipe, obtained from the endpoint that also renders the template (see Part 3), and, now, a newly added element, a button styled as a download link, that calls the getPdf() function on click.

Inside our JS file, this function will simply delegate to call the window.print().

Like so:

function getPdf() {
    window.print()
}

And, when clicking on the download button, we get the dialog box:

printing

And, voilá, we can print a single recipe from our web app into a PDF in case we want to share it and/or refer to it later.

This is a very robust approach, working across multiple browsers as well as devices, such as tablets and phones which usually come with a bundled in browser app.

Conclusion

We extended our Flask app by adding the possibility to download a recipe to a PDF.

Stay tuned for more updates!!

Oldest comments (0)