Skip to main content
Announcements
Qlik Connect 2024! Seize endless possibilities! LEARN MORE
cancel
Showing results for 
Search instead for 
Did you mean: 
Mauritz_SA
Partner - Specialist
Partner - Specialist

Qlik Sense button to export object(s) as images

Hi everyone

We have started using NPrinting, but after creating a report I saw that one of the limitations is that I cannot use Alternate states which is an integral part of my app. I have a few graphs on different sheets and was wondering whether I can create a button to export about 6 objects as images (it can do exactly what the right-click export as Image does). Ideally I would like to be able to give it Object Ids as parameters in the sheet and then click on the button and it cycles through the object Ids I configured and it exports the. This might be a bit complicated so I can event hard code the Ids in the script for now or even create multiple buttons with only one Id in each.

I was wondering whether it is possible with a widget and if anyone has a code snippet I can re-use (I am very new to widgets)?

I built a Reload-App button using an example and was hoping for a similar solution.

Reload app widget. I was hoping for something similar to export the objects.Reload app widget. I was hoping for something similar to export the objects.

Any other suggestions are welcome.

Regards,

Mauritz

Labels (2)
1 Solution

Accepted Solutions
rankassovitz
Employee
Employee

Hello there @pwagner ,

There are a few ways to go about it while developing a widget or an extension. The  main difference between the 2 will be if you want to expose a configuration panel to the app developer (extension).

When the user clicks on your custom button:

  1. Get the list of object IDs to export (hard coded list, let end user pick from objects on the sheet or let the app developer to pre-define)
  2. Loop through it and run app.getObject(ID).exportImg(settings)

Here's a snippet that will present a downloadable link for each of the objects on the sheet:

extension.js

define( ["qlik", "text!./template.html"],
	function ( qlik, template ) {
		var extId;

		return {
			template: template,
			support: {
				snapshot: true,
				export: true,
				exportData: false
			},
			paint: function ($element, layout) {
				console.log(layout);
				extId = layout.qInfo.qId;
				return qlik.Promise.resolve();
			},
			controller: ['$scope', function ( $scope, layout ) {
				var settings = { format: 'png', height: 600, width: 900 }; // you could create custom properties and gather from layout
				var app = window.app = qlik.currApp();
				var sheetId = qlik.navigation.getCurrentSheetId().sheetId;
				var sheetObjects = [];
				
				$scope.finalObjects = [];
				
				// get objects of current sheet
				$scope.getSheetObjects = function() {
					// console.log(sheetId, extId);
					app.getObject(sheetId).then(function(qSheet){
						sheetObjects = qSheet.layout.qChildList.qItems;
						// console.log(sheetObjects);
						$scope.finalObjects = sheetObjects.filter(function(object) {
							return object.qInfo.qId != extId // filter out the extension object first
								&& object.qInfo.qType != 'filterpane'; // also filter out 'filterpane' -  you can't get an image from them
						});
						// you could now present the user with checkboxes for each of those objects and only then invoke the download
						// or you could automatically start downloading all objects with one click:
						$scope.downloadObjects($scope.finalObjects);
					})
				}
				
				// loop through array and get pngs
				$scope.downloadObjects = function(idArray) {
					console.log(idArray);
					idArray.map(function(object){
						console.log(object);
						app.visualization.get(object.qInfo.qId).then(function(vis){
							console.log(vis);
						  vis.exportImg(settings).then(function (result) {
							console.log('Image download link: ', result);
							object.downloadUrl = result;
							// maybe get binaries of all files and collect them to 1 zip file using a library like JSZip
						  });
						});
					});
				}
			}]
		};

	} );

 

template.html

<div qv-extension style="height: 100%; position: relative; overflow: auto;" class="ng-scope">
	<button ng-click="getSheetObjects()">
		Download Sheet Objects
	</button>
	
	<ul ng-if="finalObjects.length">
		<li ng-repeat="o in finalObjects">
			<a href="{{ o.downloadUrl }}" target="_blank">{{ o.qData.title }}</a>
		</li>
	</ul>
</div>

View solution in original post

4 Replies
pwagner
Partner - Creator III
Partner - Creator III

Hi @Mauritz_SA 
Have you found a solution for your topic?
Regards, Patrick

rankassovitz
Employee
Employee

Hello there @pwagner ,

There are a few ways to go about it while developing a widget or an extension. The  main difference between the 2 will be if you want to expose a configuration panel to the app developer (extension).

When the user clicks on your custom button:

  1. Get the list of object IDs to export (hard coded list, let end user pick from objects on the sheet or let the app developer to pre-define)
  2. Loop through it and run app.getObject(ID).exportImg(settings)

Here's a snippet that will present a downloadable link for each of the objects on the sheet:

extension.js

define( ["qlik", "text!./template.html"],
	function ( qlik, template ) {
		var extId;

		return {
			template: template,
			support: {
				snapshot: true,
				export: true,
				exportData: false
			},
			paint: function ($element, layout) {
				console.log(layout);
				extId = layout.qInfo.qId;
				return qlik.Promise.resolve();
			},
			controller: ['$scope', function ( $scope, layout ) {
				var settings = { format: 'png', height: 600, width: 900 }; // you could create custom properties and gather from layout
				var app = window.app = qlik.currApp();
				var sheetId = qlik.navigation.getCurrentSheetId().sheetId;
				var sheetObjects = [];
				
				$scope.finalObjects = [];
				
				// get objects of current sheet
				$scope.getSheetObjects = function() {
					// console.log(sheetId, extId);
					app.getObject(sheetId).then(function(qSheet){
						sheetObjects = qSheet.layout.qChildList.qItems;
						// console.log(sheetObjects);
						$scope.finalObjects = sheetObjects.filter(function(object) {
							return object.qInfo.qId != extId // filter out the extension object first
								&& object.qInfo.qType != 'filterpane'; // also filter out 'filterpane' -  you can't get an image from them
						});
						// you could now present the user with checkboxes for each of those objects and only then invoke the download
						// or you could automatically start downloading all objects with one click:
						$scope.downloadObjects($scope.finalObjects);
					})
				}
				
				// loop through array and get pngs
				$scope.downloadObjects = function(idArray) {
					console.log(idArray);
					idArray.map(function(object){
						console.log(object);
						app.visualization.get(object.qInfo.qId).then(function(vis){
							console.log(vis);
						  vis.exportImg(settings).then(function (result) {
							console.log('Image download link: ', result);
							object.downloadUrl = result;
							// maybe get binaries of all files and collect them to 1 zip file using a library like JSZip
						  });
						});
					});
				}
			}]
		};

	} );

 

template.html

<div qv-extension style="height: 100%; position: relative; overflow: auto;" class="ng-scope">
	<button ng-click="getSheetObjects()">
		Download Sheet Objects
	</button>
	
	<ul ng-if="finalObjects.length">
		<li ng-repeat="o in finalObjects">
			<a href="{{ o.downloadUrl }}" target="_blank">{{ o.qData.title }}</a>
		</li>
	</ul>
</div>
pwagner
Partner - Creator III
Partner - Creator III

Hello @rankassovitz 

Great - thank you. It works.

I changed it from  exportImg to exportPdf.

 

Best regards, Patrick

pwagner
Partner - Creator III
Partner - Creator III

Hi @rankassovitz 

During my further tests I found out, that in the PDF I find only a certain number of lines. Unfortunately I does not correspond with the shown lines in the Qlik Sense app.

Do you have an idea what I have to change in the code of the extension?

 

pwagner_0-1675168037136.png

 

Thank you.

 

Best regards,

Patrick