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>
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));
};