javascripthtmlqliksense

Can I export a PDF file from the QLIK SENSE API not through a link but directly so that a PDF file with the desired sheet will be attached?


I manage to export from the QLIK SENSE API sheets by sheet and application IDs, but first of all I have to click on a link that leads me to download the PDF file, I was unable to cancel the action of clicking on the link

I expect an attached PDF file to be sent to me through the QLIK SENSE API without having to click on a link

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Qlik Sense Mashup</title>
    <meta charset="utf-8">
    <script src="https://pa-qliksense.aviv.gov.il/sense/app/appId"></script>
    <meta http-equiv="content-type"="text/html; charset=UTF-8">
    <meta name="HandheldFriendly" content="True">
    <meta name="MobileOptimized" content="320">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta http-equiv="cleartype" content="on">
    <script src="../../resources/assets/external/requirejs/require.js"></script>
    <style>
        /* Spinner CSS */
        .spinner {
            border: 16px solid #f3f3f3;
            border-radius: 50%;
            border-top: 16px solid #3498db;
            width: 120px;
            height: 120px;
            animation: spin 2s linear infinite;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        #spinnerContainer {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(255, 255, 255, 0.8);
            z-index: 9999;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        #spinnerContainer.hidden {
            display: none;
        }
    </style>
</head>
<body style="overflow: auto">
    <div id="spinnerContainer">
        <div class="spinner"></div>
    </div>
    <div id="CurrentSelections" class="qvobjects" style="position:relative; top:0; left:0; width:100%; height:38px;"></div>
    <div id="downloadLinks" style="margin-top: 20px;"></div>

    <!-- Automatically trigger export on page load -->
    <script>
        window.onload = function () {
            var urlParams = new URLSearchParams(window.location.search);
            var appId = urlParams.get('appId');
            var sheetId = urlParams.get('sheetId');
            var fieldName1 = urlParams.get('fieldName1');
            var fieldValue1 = urlParams.get('fieldValue1');
            var fieldName2 = urlParams.get('fieldName2');
            var fieldValue2 = urlParams.get('fieldValue2');
            var fieldName3 = urlParams.get('fieldName3');
            var fieldValue3 = urlParams.get('fieldValue3');
            var fieldName4 = urlParams.get('fieldName4');
            var fieldValue4 = urlParams.get('fieldValue4');
            var fieldName5 = urlParams.get('fieldName5');
            var fieldValue5 = urlParams.get('fieldValue5');
            var fieldName6 = urlParams.get('fieldName6');
            var fieldValue6 = urlParams.get('fieldValue6');
            var fieldName7 = urlParams.get('fieldName7');
            var fieldValue7 = urlParams.get('fieldValue7');
            var fieldName8 = urlParams.get('fieldName8');
            var fieldValue8 = urlParams.get('fieldValue8');

            exportData(appId, sheetId, fieldName1, fieldValue1, fieldName2, fieldValue2, fieldName3, fieldValue3, fieldName4, fieldValue4, fieldName5, fieldValue5, fieldName6, fieldValue6, fieldName7, fieldValue7, fieldName8, fieldValue8);
        };

        function exportData(appId, sheetId, fieldName1, fieldValue1, fieldName2, fieldValue2, fieldName3, fieldValue3, fieldName4, fieldValue4, fieldName5, fieldValue5, fieldName6, fieldValue6, fieldName7, fieldValue7, fieldName8, fieldValue8) {
            var prefix = window.location.pathname.substr(0, window.location.pathname.toLowerCase().lastIndexOf("/extensions") + 1);
            var config = {
                host: window.location.hostname,
                prefix: prefix,
                port: window.location.port,
                isSecure: window.location.protocol === "https:"
            };

            require.config({
                baseUrl: (config.isSecure ? "https://" : "http://") + config.host + (config.port ? ":" + config.port : "") + config.prefix + "resources"
            });

            require(["js/qlik"], function (qlik) {
                qlik.setOnError(function (error) {
                    console.error('Error:', error);
                    alert('Error: ' + error.message);
                });
                qlik.theme.apply('horizon');

                // Open app
                var app = qlik.openApp(appId, config);

                // Clear all selections before applying new ones
                app.clearAll().then(function () {
                    // Apply selections
                    app.field(fieldName1).selectValues([fieldValue1], true, false);
                    app.field(fieldName2).selectValues([fieldValue2], true, false);
                    app.field(fieldName3).selectValues([fieldValue3], true, false);
                    app.field(fieldName4).selectValues([fieldValue4], true, false);
                    app.field(fieldName5).selectValues([fieldValue5], true, false);
                    app.field(fieldName6).selectValues([fieldValue6], true, false);
                    app.field(fieldName7).selectValues([fieldValue7], true, false);
                    app.field(fieldName8).selectValues([fieldValue8], true, false);

                    // Export entire sheet to PDF
                    app.visualization.get(sheetId).then(function (object) {
                        object.exportPdf({
                            documentSize: 'A4',
                            aspectRatio: 0,
                            orientation: "landscape",
                            objectSize: { height: 1280, width: 1920 }
                        }).then(function (pdfExportData) {
                            // Hide spinner
                            document.getElementById('spinnerContainer').classList.add('hidden');
                            // Create an invisible link element
                            var link = document.createElement('a');
                            link.href = pdfExportData;
                            link.download = 'exported_dashboard.pdf';
                            link.style.display = 'none';
                            document.body.appendChild(link);
                            // Trigger the download by clicking the link
                            link.click();
                            // Remove the link element from the document
                            document.body.removeChild(link);
                        }).catch(function (pdfError) {
                            console.error('Error exporting dashboard to PDF:', pdfError);
                            alert('Error exporting dashboard to PDF. See console for details.');
                            document.getElementById('spinnerContainer').classList.add('hidden');
                        });
                    }).catch(function (error) {
                        console.error('Error getting current selections object:', error);
                        alert('Error getting current selections object. See console for details.');
                        document.getElementById('spinnerContainer').classList.add('hidden');
                    });
                }).catch(function (error) {
                    console.error('Error clearing selections:', error);
                    alert('Error clearing selections. See console for details.');
                    document.getElementById('spinnerContainer').classList.add('hidden');
                });
            });
        }
    </script>
</body>
</html>

Solution

  • Why not use a backend server (like Node.js, Python, etc.) to handle the API call and the PDF generation and call the Qlik Sense API to export the desired sheet as a PDF then the backend server can download the generated PDF and either send it as an attachment in an email or respond to the client with the PDF as a file download.

    Backend Server Setup (Node.js)

    const axios = require('axios');
    const fs = require('fs');
    const express = require('express');
    const app = express();
    
    app.get('/export-pdf', async (req, res) => {
        try {
            const { appId, sheetId } = req.query;
    
        // Call the Qlik Sense API to export the sheet to PDF
            const pdfResponse = await axios({
                method: 'post',
                url: `https://your-qlik-sense-server/sense/app/${appId}/export/${sheetId}`,
                headers: {
                    'Authorization': 'Bearer your-authorization-token'
                },
                responseType: 'arraybuffer'  // Ensures the response is treated as a binary file
            });
    
        // Set the correct headers for PDF file download
            res.setHeader('Content-Disposition', 'attachment; 
    filename="exported_dashboard.pdf"');
            res.setHeader('Content-Type', 'application/pdf');
    
        // Send the PDF file as the response
            res.send(pdfResponse.data);
        } catch (error) {
            console.error('Error exporting PDF:', error);
            res.status(500).send('Error exporting PDF');
        }
    });
    
    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
        console.log(`Server is running on port ${PORT}`);
     });
    

    Frontend Call

    window.onload = function () {
    const appId = 'your-app-id';
    const sheetId = 'your-sheet-id';
    
    fetch(`/export-pdf?appId=${appId}&sheetId=${sheetId}`)
        .then(response => response.blob())
        .then(blob => {
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.style.display = 'none';
            a.href = url;
            a.download = 'exported_dashboard.pdf';
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
        })
        .catch(error => console.error('Error fetching the PDF:', error));
    };