One of the more advanced feature in QlikView is alternate state. It alllows you to have several different selections active at the same time. With set analysis expressions you can then combine your selection sets to gain valuable insights.

While alternate states are not exposed in the built-in Qlik Sense client, you can easily add them to your custom extension with just a few lines of code. Let’s see how.

Step 1: add a property panel field

The qStateName property already exists (check the Qix Engine API), so a first step is to map it to the property panel. Lets create a new section under “Addons”:

This assumes a HyperCube, $ is the default state which is always there. This is already enough for alternate state to work in your extension. If you enter a valid alternate state name in the property panel your extension will be connected to it. Problem is there has to be an alternate state in the app, and you need to know it’s name. Lets do something about that.

Step 2: add a listbox with existing alternate states.

Lets convert our property panel to a dropdown list, where the app developer can choose what state the object should be connected to. We do this by setting the component to ‘dropdown’ and adding a function to return the options:

Alternate states ar listed in the app layout structure, so we need to get the app layout and format the states in the format the property panel dropdown wants. The default state ‘$’ is not in the list, so we need to add that ourselves. For this to work you need to have the qlik module available in your extension.

Now you will have a dropdown list in your extension property panel, something like this:

Still doesn’t look much, does it… But it does it’s job. Now we just need a way to create those alternate states.

Step 3:Creating the alternate states

Well, actually you need to do this first. But there are different ways to achieve this:

  • there are extensions for this
  • you could do it in Engine API explorer, since its really a one-time thing
  • or, you could add it to the property panel.

The property panel is not really meant for this, since we are not updating the object properties, but the app properties, but still it’s pretty easy to do. You can add something like this to the property panel:

It’s really not more complicated than that. You will get an inputfield in the propertypanel. If the user writes anything in that field, an alternate state will be created. It will then show up in the listbox, so you can use it in your extension.

Conclusion

It’s really not at all difficult to add alternate state support to your extension. Probably you should do something to show the user that this chart belongs to an alternate state: you can use the header for that, or add some styling or an icon for charts that are in another state. I’ll leave that for you.

A few weeks ago I wrote a post about a pattern I have used to make Qlik Sense apps more flexible and allow the user to choose what visualizations to show.  Feedback I got on this(from Rob Wunderlich) is that there is a performance problem with pick(), that Qlik Sense does not optimize pick calls quite as well as you might think, that it might evaluate function calls where the values are not actually used.

I vaguely remember this from Master Summit for Qlik  where I believe it was mentioned. At the same time I do know that Qlik from time to time makes improvements in the optimization, so it might not be true anymore. Anyhow, this is something you could easily verfify. And I’ve got a tool to make at least a first assessment of this, the Developer Tools extension. I originally made this to help finding id’s for visualizations, but later has added some timing features to it, that can give us a rough idea about performance in your visualizations.

Setup visualizations

To do this I made a copy of the example used in my previous post. You find it here. In it I made a new sheet and copied one of the visualizations using pick() into it. I chose the pie chart (not because I like pie charts, but because I wanted one with some data in it). I then made a copy of it, and in the copy removed all pick() calls, together with alternatives 2 and 3 in that call, leaving only the first one, which is the expression that will actually be used of the three in pick(). And I add the DevTool extension to the same sheet.

Run the test

When all is ready, I switch into analyze mode and click  on the DevTool button, which creates popups for the two charts. I then make some selections, use back and forward, and I get the following result:

The left chart is with pick(), the right one without. The most interesting figure is the one at the bottom right, the maximum calculation time. As you can see there is a significant difference: 147 ms compared to 57 ms.  Seems like Rob is wright: there is (still) a performance problem with pick(), even though in my test case calculation time is so small that users will probably not notice.

Conclusion

This is a very rough test. It’s main advantage is that you can do it quickly. Since there is such a clear difference between the two alternative the result that pick() is considerably slower can be trusted. And the fact that the no-pick alternative actually takes some time (57 and not 5 msek) means that there is some calculation going on, just taking the result from the cache would be faster.

 

 

One of the main uses of the Variable extension for Qlik Sense is to allow users to quickly with a click on a button switch dimensions or measures in a chart. This has been described in Qlik Community here and here.

But perhaps you want to change more on the click of a button. You need to change not only a dimension or a measure, but several. And a title, or a subtitle or whatever. In that case you can use the Qlik pick function:

pick(n, expr1[ , expr2,...exprN])
n is an integer between 1 and N.
pick( N, 'A','B',4, 6 ) 
   returns 'B' if N = 2
   returns 4 if N = 3

 Variable and Pick()

The combination of Pick() and a variable can be very powerful. It also has another advantage. Sometimes the expressions you need to switch between are fairly complicated. Setting them up in the property panel of the variable extension can be difficult, and it’s not really the right place for Qlik expressions. Using the pick function helps you keep your expressions out of the property panel and instead where they belong, in the chart setup or in a measure or dimension definition.

To illustrate this I’ve made a small example, available in the Github repository here. To try it you of course need to install the actual extension. If you don’t have that already, you’ll find it here. I have called it Switch dashboard, because what it does is that it in the same area of the sheets allows the user to switch between three different setups, Margin, Sales and Budget (the actual data and the charts are taken from the Consumer Sales demo).

Initially when you open the app it looks like this:

Click on the Sales button and it will change to:

Just about everything has changed: another KPI is displayed, dimension in the middle (donut!) chart, measure in both charts, titles. And if you click the Budget button, you will see a third setup, I’ll leave that to you to verify.

Setup

To set this up you use classic Qlik features, like script statements and expressions, using the pick function. But you could also use Qlik Sense dimensions and measures. Lets see how its done:

Step 1: define the variable and set default value in the script.

First we define the variable we will use. Using standard Qlik naming conventions I’ve called it vDashboard and added it to the script:

SET vDashboard = 1;

Remember that pick numbering starts with 1, so do not use zero. The plan is that 1 should be our first dashboard, Margin, 2 should be Sales and 3 should be Budget.

Step 2:  set up a chart dimension

Now we use the variable, together with the pick function to define dimensions. In the donut chart I’ve defined the dimension like this:

=pick(vDashboard, [Product Group Desc], [state_name], [Sales Rep Name])

This will mean that we use different dimensions depending on the value of the vDashboard variable.

Step 3: Define measures

But we want to make the measures switchable too. But since we will use the same measure in several places, I have chosen another method for measures. I have defined two master measures, called (not too much creativity here, I’m afraid) ‘Dashboard KPI 1’ and ‘Dashboard KPI 2’. Definition of those looks like this:

pick(vDashboard,
Sum([Sales Margin Amount])/Sum([Sales Amount]),
(sum([YTD Sales Amount])-sum([LY YTD Sales Amount])*0.2)/sum([LY YTD Sales Amount]),
Sum ([Budget Amount])/Sum ([Actual Amount]))

I then use those measures in the charts.

Expressions in Qlik can be a lot more complicated, so it’s an advantage to be able to use the expression editor and get the syntax correct for this. Also I have been consistent in the formatting, so that each pick alternative is on its own line.

Step 4: Labels etc

Finally we want to make sure that chart titles reflect the content. Luckily we can use pick() in the title definition too:

=pick(vDashboard,'Margin Amount Over Time','Sales Over Time','Budget Amount Over Time')

We can use this approach everywhere in the property panel wher an expression is allowed. (A note for you extension developer: make sure that as much as possible in your extension can be set up with expressions, that will increase the flexibility of your solution a lot).

Step 5 (and final): Set up the extension

Finally we need to make it possible for the user to actually change the value of the vDashboard variable, thereby switching the dashboard contents. We do this by adding the Variable extension to the sheet and setting it up like this:

As you can see this is really straightforward. We use the values 1, 2, 3 etc and labels showing what we display for the three alternative versions.

A more advanced setup is using the new dynamic values option, and have a Qlik expression returning the alternatives. That way you could have a different set of dashboards for different users. Only remember that the first alternative needs to be available for all users, since it will be the default.

Conclusion

The combination of the pick function and a variable (and the variable extension) makes really powerful solutions possible. And note that this is classic Qlik skills that are needed: Qlik expressions and the well-known pick function. You do not need to start with web development for this.

Sometimes when you are building a Qlik Sense extension you need to get access to system data. This is espescially true if you are trying to build something a bit more generic. Perhaps you need a list of fields, or dimensions, or measures. Or you need to work with variables.

If you are new to Qlik Sense development you might look in the API documentation for methods to get the data you need. Don’t do that!! Qlik Sense extension model is based on the idea that you use one Generic Object, described in the extensions initialProperties, and modified by the user in the property panel, and possibly programmatically (but that’s really advanced). So while using the API methods to get additonal data is the approach to use in mashups or Web apps that access Qlik data, you should avoid using them in a masup.

Why you shouldn’t

If you do use these api calls in your extension, you will get problems:

  • you might easily get a memory leak, or a ‘Generic Object leak’, where you create lots of Generic Objects
  • you can easily lose contral of all callback functions running when the generic objects are revalidated
  • if the user makes a snapshot, the API calls will access the latest version of the data, not the one in the snapshot and possibly give the wrong data
  • if the user tries to export your extension to PDF or Excel it might break, since the service responsible for those export does not have access to live data, only to the snapshot

If you absolutely must use these calls, you should at least turn export to PDF and Excel of and not allow snapshots of your extension.

What you should do instead

Luckily there are alternatives. These API calls all create Generic Objects, but since the Generic Object is a very flexible structure, you can actually configure the Generic Object behind your extension to provide the data you need. Here is a little table of what you could use:

You needDo not use API callInstead add to initialProperties
List of fieldsapp.getList("FieldList")qFieldListDef
List of measuresapp.getList("MeasureList")qMeasureListDef
List of dimensionsapp.getList("DimensionList")qDimensionListDef
List of variablesapp.getList("VariableList")qVariableListDef
Variable valueapp.variable.getContent(..)qStringExpression or
qValueExpression

You find a working example of this in my syslist extension just don’t use it, it’s meant as examples of how to get the data and doesn’t really do anything useful. But do grab the initialProperties part you need for your extension.

It looks like this:

When should you use these API calls

Well, no rule without an exception. While you should avoid using these calls in the API for the rendering part of your extension, you should use them in your property panel, if you for example need to provide a list of fields to the user. And in a mashup, they are definitely very useful. And the API has other calls, which you might want to use, but that vill mainly be when the user does something, like clicking a button etc.

Example of Variable use included in the extension

A new version of my Qlik Sense Extension Variable is now available.

No new functionality, but some minor internal changes:

  • revised build, CSS is no longer a separate file, but bundled in the javascript file
  • reverted back to using the Capabilities API
  • some new examples of use

This release is part of the preparation for the certification of the extension. Read more about that here. This extension is however still not certified.

About a year ago, I took a first look at Qlik Sense on demand app generation for a customer. Their problem was not really using big data, but rather that the data the needed for some analysis was simply too big to handle in a Qlik Sense ( or QlikView) app. They had to limit the data to just a shorter time period to make it run at all. Our conclusion at the time was that On Demand App Generation might be the right the right tool, but we had to prioritize other projects and did not complete the project.

Now, about a year later, we have the time to look into it again. And while I think the core concepts and functionality is the same, it has had a facelift, and feels much more like a product ready for production.

Improved user interface

The on demand app generation feature consists of a master or selection app and multiple on-demand apps. The user uses the the selection app, which contains aggregated data, to select a subset of the total data. He then generates an on-demand app, with detailed information about that subset.

The interface for this has been improved a lot. Previously keeping track of your on-demand apps was difficult, now you can find them in the selection app.

All your generated apps are listed in the popup for the selection app, together with information about when they where created and the selections they are based on in the selection app. You can also manage your generated app here, delete it when you are ready with it, reload it with the same selections but new data and open it.

Loading data into the on demand app

In many respects developing on demand apps is just like developing any Qlik Sense app. That’s part of the strength of the feature – you can use your Qlik Sense knowledge for on demand apps too, visualizations are the same, much of the load script will also be the same. What’s new is the connection between the selection app and the on demand app: how do you get the users selections into the ODA, and how should you write the load script.

When we worked with this a year ago, we used Qlik Sense varibles and the script snippets published in Qlik Sense help around using the variables to generate script statements. These snippets helps you generate selection queries in the form of SQL SELECT’s to fetch the data. Our use case is somewhat different: our problem is that we have internally generated data that is simply to big for one app, but the data is not in an SQL database (even if the original source is a database), but in QVD files. This makes it possible to use a much easier method: we can have the selected values inserted into inline tables, and then use them in ordinary LOAD statements.

Using an inline table with the selected values

The first step is to create the inline table:

selected_item_tab:
LOAD * INLINE [
 SELECTED_ITEM
 $(odso_ITEMID){"quote": "", "delimiter": ""} 
];

Item ID’s for all selected and optional items will then be injected into the script. By using prefix ‘odso’ we allow the user to make selections on any level in the ITEM dimension, like product groups etc.

You can then use the inline table when you load your actual data:

LOAD
  ITEM_ID,
  ...
FROM .....qvd (qvd)
WHERE EXISTS(SELECTED_ITEM,ITEM_ID);

This will filter the data so that only selected items are included. You can also combine several dimensions, like time or geography to further reduce the data. No variables or string parsing is needed. So far this seems to work well.

Getting used to the generated apps

Perhaps the most difficult part of the On Demand app generation remains. The generated apps will only select a subset of the data, and in some cases it won’t be obvious what the subset is. Qlik users are not really used to this. Selections will be a two-step process, where the actual analysis will work as we are used too, but the initial selection cannot be immediately changed. This is a new way of working for users. Also totals calculated in the generated app might be useful for reference, it must always be remembered that they are just for a subset. We will try to make the initial selections clearly visible to the user of the generated app, and perhaps we should also try to bring over some summarys etc for the complete data, but still users will have to think differently. That might be the real challenge with this.

One of the great new features in Qlik Sense is snapshots and storytelling. It allows you to create a snapshot of your visualizations, with the current selection state, and then include the snapshot in a story. Behind the scenes Qlik Sense also uses snapshot for export to PDF, PowerPoint and image. This makes it even more important for you to make your extension work well with snapshots. Sometimes this is however not easy…

The basics

To turn snapshots on, you need to include a few lines in your extension:

This will give you a context menu in the client with alternatives to create snapshot and export the visualization. That might be enough, but it might not be enough. To verify it you should:

  • create a snapshot of your extension, include it in a story and verify that it works
  • export your extension to PDF and/or PowerPoint (possibly also image)
  • and export the story to Powerpoint/PDF

You visualization is actually used in three contexts, that are somewhat different:

  1. the normal analyse mode, with live data, affected by changes in selection state
  2. the snapshot/story mode with a snapshot of data and the selection state as it was when the snapshot was created
  3. the export mode, which is also based on a snapshot, but run in a separate service on the server

To make it actually work in all, you might need to do some more work.

Make Qlik Sense wait for your extension

One problem, mainly in export, is to let Qlik Sense know when your extension actually is ready with the rendering. You might get just an empty area in your powerpoint, or just the header but no content. This might be because the image is taken before your extension is ready.

The mechanism to fix this is a javascript concept called a Promise. Your paint method should return a Promise, that resolves when the rendering is ready. Qlik Sense will then wait until the Promise is resolved and then grab the image.

This is described where briefly in Qlik Sense help under ‘Set up “finished rendering” notification, like this:

This will return a Promise, that immediately resolves. This might not be good enough, since you might want to wait for something until you resolve. In my case, I used highcarts and highcharts has a callback function that will be called when rendering is ready. The final solution is like this:

So, I create a deferred object before calling the Highcharts rendering method. I can then return the promise that belongs to the deferred, but I do not resolve it until Highcharts tells me that rendering is complete, actually I had to add an additional delay of 1 second to make sure. There is currently no documentation of qlik.Promise in Qlik Sense help, but you can look in the angularjs documentation.

Turn animations off

If it’s still not working, you should take a look at animations. Animations in analyse mode are good (if used the right way…) and might help the user discover insights in their data, but in export they should be turned off.

In Highcharts there are actually two flags you should turn off to diable animations. It might be enough to turn off just one of them, but why not both:

The isSnapshot flag which I use to determine if we are in analyse mode or in snapshot (story or export) is undocumented, so this solution might break in future Qlik Sense versions, but in September 2017 it works.

Sometimes in your extension you need to acces the QIX Engine API. You might need to make or clear selections, apply a bookmark or something else. Traditionally you would use the Capabilities APIs for this. You would load the qlik module, get hold of the app with the help of the currApp() method, and call whatever function you needed.

But there is another way. You could do it the way the built-in client does, and use enigmajs instead. Enigmajs creates a javascript wrapper around the QIX api, a wrapper that includes all methods defined in the version of QIX your system is using. Qlik actually has open-sourced enigmajs, you can read more, and download it from the Github repository.

Enigmajs features

Important features of enigmajs:

  • it includes the complete QIX API for the actual version of QIX, while the capabilities API just includes a subset
  • it only includes the QIX Engine API, while the capabilities APIs wraps some client-side functionality too
  • methods calls return a Promise, that resolves when there is a response available
  • it handles the invalidation of objects as the selection state changes so it works well from inside an extension

Unlike the Capabilities APIs, enigmajs does not come with a lot of dependencies on requirejs, angularjs and Qlik Sense client code. This makes it well suited for use in envorinments where you use other frameworks, like react or future frameworks we have not heard of yet. Of course if you’re using it inside an extension, you already have all of these dependencies, so that is not so important.

Note that Qlik flags enigmajs as experimental in the current release. I would be very surprised if it goes away any time soon, but details in the implementation might change, you need to be aware of that.

Finding enigmajs in an extension

Qlik Sense creates a server side Generic Object for each instance of your extension (for all built-in charts too, actually). Around that Generic Object will be a javascript wrapper that exposes all the methods available. In the extension you can find it at:

this.backendApi.model.enigmaModel

It will expose all the methods defined in the Generic Object QIX engine API. As you can see, there are a lot of methods. It also has an app property, that exposes QIX Engine API app object. And the app has a global property, that is a wrapper around QIX Engine Global. This gives you access to the complete QIX Engine API.

An example

I have converted my Variable extension for Qlik Sense to use enigmajs instead of the Capabilities API, as versions before 4.0 did. The key call of the extension is after the conversion like this:

function setVariableValue(ext, name, value) {
        return ext.backendApi.model.enigmaModel.app.getVariableByName(name).then(function (v) {
            return v.setStringValue(value);
        });
    }
The parameter ext is a reference to the extension itself. Since methods return a Promise, I can use the then method to run an additional command after the first command resolves. The getVariableByName reurn an enigmajs wrapper aroud a QIX Engine Variable

Conclusion

If you need access to QIX Engine API from within your extension, enigmajs can help you with that. Unlike the Capabilities API it provides wrappers for all methods. But you should be aware that it only wraps engine api, not client-side functionality. It however works nicely within the client and invalidation and refresh of objects will work as expected.

While error handling in a Qlik Sense mashup is not automatic, and the documentation is not that good, it’s really not that difficult to get it right. But there are a few things you need to know.

Why do you need it?

Your mashup might work perfectly well when you are testing it. All code is verified, all object id’s refer to objects that actually exist in the app, you have solved the problem with appid’s that differ between your development environment and production. Still there are situations where you need your error handling:

  • unauthorized users: the Qlik Sense hub makes sure to only show apps the user has access to, but for mashups there is no such mechanism, so it’s up to you to handle this situation. Qlik Sense will not allow the user to actually open the app, but he will probably be able to open the mashup, so you will need to handle the situation where he has no access to the app
  • timeout: if your users are inactive, their sessions will be closed. This means that they will not be able to continue (or restart) working in your mashup without reconnecting, most likely by doing a reload of the mashup. You need to tell the user what has happened and what they should do.

Api support

To help you with this is the setOnError method. It allows you to register a function that is called whenever an error occurs. This is both for errors that are the result of a call, like opening an app that does not exist (or the user is not authorized to access), and errors that are generated from the server, like timeouts. Obviously a good start is to display the error.

qlik.setOnError(function (error) {
        // TODO:error handling
        console.log('Qlik error', error);
        $("#errmsg").html(error.message).parent().show();
 });
Or perhaps, a angular version:
//create an array for errors
$scope.errors = [];
qlik.setOnError(function (error) {
    // TODO:error handling
    console.log('Qlik error', error);
    $scope.errors.push(error);
});
and in your template something like this:
<div ng-repeat="err in errors" class="alert">{{err.message}}</div>
Then just add a button for clearing errors ($scope.errors.length = 0 would do the trick) add some styling and you’ve got a first attempt.

Add some intelligence

But for some errors showing the error is not enough. For example if the user gets a timeout, he needs to refresh before continuing to work. If the user has no access the rest of your mashup will probably be empty (well if you show data from other sources they might be available).

To do this we need to use the error code we get with the message. As far as I know there is no official documentation of Qlik Sense error codes, but if you’ve got Qlik Sense desktop installed, you can easily find one. Just start Qlik Sense Desktop and in your browser go to:

http://localhost:4848/resources/translate/en-US/engine.js

As you might have guessed, this file contains, among other things, error code from QIX Engine. After you formatted this file, you will find something like this in it:

"ErrorCode.-128": "Internal engine error",
"ErrorCode.-1": "Unknown error",
"ErrorCode.0": "Unknown error",
"ErrorCode.1": "Some data is not correctly specified.",
"ErrorCode.2": "The resource could not be found.",
"ErrorCode.3": "Resource already exists.",
"ErrorCode.4": "Invalid path",
"ErrorCode.5": "Access is denied",
"ErrorCode.6": "The system is out of memory.",
"ErrorCode.7": "Not initialized",
"ErrorCode.8": "Invalid parameters",
"ErrorCode.9": "Some parameters are empty.",
"ErrorCode.10": "Internal error",
"ErrorCode.11": "Corrupted data",
"ErrorCode.12": "Memory inconsistency",
"ErrorCode.13": "Action was aborted unexpectedly.",
"ErrorCode.14": "Validation cannot be performed at the moment. Please try again later.",
"ErrorCode.15": "Operation aborted",
"ErrorCode.16": "Connection lost. Make sure that Qlik Sense is running properly. If your session has timed out due to inactivity, refresh to continue working.",

So there it is, error code 16 means connection lost, so if we get that we should encourage the user to refresh, perhaps display a button or something and perhaps even disable stuff that won’t work, like selections etc.
The error code from QIX engine will be in error.code in the object that is the parameter to our error funtion, so we can simply test that:

qlik.setOnError(function (error) {
     // TODO:error handling
     console.log('Qlik error', error); 
     $scope.errors.push(error);
     if(error.code === 16){
        $scope.showRefresh = true;
     }
});

Handle proxy errors

But we’re not quite through yet. When you install your mashup on Qlik Sense server, you’ll notice that not all error object have the ‘code’ field. That’s because proxy errors have another format. Instead of the code field, there is a method field. And they’re not in the engine.js file. Instead you need to look in:

http://localhost:4848/resources/translate/en-US/client.js

In it you will find the proxy errors:

"ProxyError.OnEngineWebsocketFailed": "Connection to the Qlik Sense engine failed for unspecified reasons. Refresh your browser or contact your system administrator.",
"ProxyError.OnLicenseAccessDenied": "You cannot access Qlik Sense because you have no access pass.", "ProxyError.OnLicenseAccessDeniedPendingUserSync": "Your access pass credentials are being synced. Refresh your browser or contact your system administrator.",
"ProxyError.OnNoEngineAvailable": "No available Qlik Sense engine was found. Refresh your browser or contact your system administrator.", "ProxyError.OnSessionClosed": "Your session has been closed. Refresh your browser to continue working.",
"ProxyError.OnNoDataPrepServiceAvailable": "Data Profiling service is not available.",
"ProxyError.OnDataPrepServiceWebsocketFailed": "Data Profiling service connection failed. Refresh your browser.",
"ProxyError.OnSessionTimedOut": "Your session has timed out. Log back in to Qlik Sense to continue.",
So there we are, we need to handle also OnSessionClosed and OnSessionTimedOut. This gives us something like this:
qlik.setOnError(function (error) {
     //error handling
     console.log('Qlik error', error);
     $scope.errors.push(error); 
     if(error.code === 16 || ["OnSessionTimedOut","OnSessionClosed"].indexOf(error.method)>-1){ 
        $scope.showRefresh = true;
     }
});
And that’s it, we now have error handling thats shows error messages to users and sets a flag when the user should refresh. We can then use the flag to for example display a refresh button and/or disable interactivity like selections.

One of the most popular new features in Qlik Sense is snapshots and storytelling. When you discover something interesting in your Qlik Sense app you can take a snapshot of a visualization, including its selections and data, and then build a story where you use it. And you can recreate the selections from the snapshot and drill deeper into your data or look at it from another angle.

In many cases this works automatically for your extension too, but sometimes it doesn’t. In recent versions of Qlik Sense new features, like printing and export to PDF are also built on the snapshot feature, which makes it even more important for it to work. So here is a description of how it works and what you need to do to make your extension work in snapshots.

How does snapshots work?

You create a snapshot by clicking the camera icon in the visualization context menu.  Qlik Sense will then make a copy of the data used for the rendering, known as the layout. This structure is then included in a new bookmark, that is created in Qix engine. Note that it’s not the HTML that is saved, nor is it a bitmap of the actual visualization on the screen. It’s the data.

So when the user wants to look at the snapshot, the data is loaded from the bookmark, Qlik Sense then checks what extension was used to visualize it, loads the extension, creates an object using the visualization, and calls the paint method of the visualization. But the layout parameter will not contain live data from the current selection state, it will contain data from the snapshot.

What this means for your extension

For snapshots to work your extension should use only the layout when rendering.  You should not try to use the capabilities APIs to access data dynamically. Most likely it will not work, and if you manage to get it working, the data you get will be live and not reflect the state when the snapshot was taken. So make sure you add the data you need to the properties structure instead.

Also you need to keep the layout clean. It is good practice to treat it as read-only, adding nice-to-have references make make it impossible to serialize the layout, and creating the snapshot might fail.

And don’t forget to test creating snapshots from your extensions. Also verify that printing and exporting to PDF works, very likely your users expect them to.