Featured

Work during the pandemic

The current pandemic means I have problems taking contracts where I need to travel outside of Sweden or Denmark. I can however take on remote contracts, and most of the work I do can be made remotely, so please get in touch if you need help with Qlik Sense mashups, extensions or integration. Stuff I can help you with:

  • development of mashups and extensions
  • lower level integration using the Qlik Engine API, possibly together with other APIs
  • extension and mashup strategy: when and how to use them, what to check for in an extension or mashup
  • maintenance of extensions
  • troubleshooting and performance problems
  • validating (and fixing) extensions and mashups with new Qlik Sense versions

Recently I have helped customers and partners wityh among other things:

  • make extensions work with NPrinting (pretty common problem, I’m afraid)
  • building a generic write-back solution with extension and back-end service
  • advanced extension development
  • making sure extensions work on a mashup hosted on a web server (not Qlik)

Best way to reach me is through mail: erik at upper88.com

Trying Qlik Sense Business API’s

Much of Qlik’s focus is today on their cloud products. Getting up and running with Qlik Sense Business (the name Qlik uses for their entry-level cloud product) is easy. And even if the hub is different and there is no QMC, it feels familiar. After all it’s the same engine behind the scenes. Many (probably most) extension will also work, since the extension API is the same, and the Capabilities API also the same – almost. But even though the methods are all there, some of them actually don’t give the same result.

The global object in the Capabilities API

The differences I have found are in the global object, as should be expected. (documentation is here). So let’s try it.

The first method is getAppList(). In Qlik Sense Desktop or Qlik Sense Enterprise (which is Qlik’s name on the product you install yourself on a windows server) this method will give you a list of all apps the currently authorized user has access to. In Qlik Sense Business it still works, but if you try it, it looks something like this:

In my Qlik Sense Business hub, I’ve got four apps, but getAppList only returns the one I am currently using. So if your extension uses getAppList to create a list of other apps, it won’t work in Qlik Sense Business.

Another frequently used method in the global object is getAuthenticatedUser(). You use it to find out the users id. In Qlik Sense Desktop you’ll get ‘Personal\\Me’, in Qlik Sense Enterprise you’ll get a string containing UserId and UserDirectory. In qlik Sense Business it looks like this:

So, while the format is the same as in Qlik Sense Enterprise, the content is different. The UserDirectory is empty, and the UserId is actually the IdP subject you can find in the cloud console (IdP stands for Identity Provider).

callRepository

The Capabilities APIs has one method designed to call the repository, originally built to call Qlik Sense Enterprise REST API called callRepository(). It is marked as Deprecated, but it is still there in Qlik Sense Enterprise, and looks like it’s there in Qlik Sense Business too. What happens if we try it?

Qlik Sense Cloud has the REST endpoint /api/v1/items to list apps the user has access to. If we try it, it looks like this:

We do get a warning in the console, but the call works, the data array actually contains the four apps I’ve got in my Qlik Sense Business hub. But since it is deprecated we probably shouldn’t use it but use some standard method of making a REST call instead.

Add Sense Chrome 1.3.0: corrections and changed icons

Version 1.3.0 of my Chrome Extension Add Sense is now available here. If you already have it installed, you should get the update automatically. These are the changes

Changed icon set

The extension now uses Qlik’s Leonardo UI instead of material design icons. The loading of Material Design icons does not work without configuration changes in Qlik’s cloud products, while Leonardo UI is already loaded.

Fixed bug when properties where treated like HTML elements

Sometimes expressions containing set analysis where destroyed in the tool. Mostly this happened when there was a letter immediately after the < character. That has now been fixed.

Other changes

If the visualization on screen is in the library, you previously only got the link (containing the id of the master visualization) in the property popup. Now you get the master objects properties.

The default filename when you save properties to file now contains the id of the visualization. You can still use another filename if you want to.

Qlik Sense and CSS revisited

I while ago I wrote a post on using CSS in Qlik Sense, with focus on extension development (you find it here). Much of it is of interest also if you are making Themes. While that post is still relevant, there are some recent changes in the Qlik Sense client that are important to know.

Inline styles

Qlik Sense now uses more inline styles. An example is headers, that are now styled something like this:

element.style {
    font-size: 1.15385em;
    font-family: "QlikView Sans", sans-serif;
    color: rgb(128, 128, 128);
    padding-right: 0px;
    padding-left: 0px;
}

This is because you can now actually set header color etc for some of the built-in charts. Where this is possible you will find a ‘Styling’ button in the property panel under ‘Presentation’, that gives you some new options:

Based on your settings here, Qlik Sense will create an inline style. Even if you do not have this section (looks like it is undocumented, if you find any documentation on it, please let me know) Qlik Sense will still create inline styles. Since it is an inline style, you will need to use !important if you want to override it, whether in a theme or in an extension, something like this:

 .qv-object-qlik-variable-input  .qv-object-title {

   color:red !important;

}

(I answered a question on this recently here)

Hiding the expand button

A common request is that you want to disable the maximize functionality for some objects. While expanding a chart or a table to full-page is often a good feature, for many extensions, like buttons, or most text objects it makes no sense. This once used to be possible to do with some CSS, but because of changes in the HTML structure is no longer possible. But in the latest release there is a new flag under Appearance/General that allows you the disable the hover menu:

This is almost the same, though not quite:

  • everything in the hover menu will disappear
  • instead you can use the context (right-click) menu, where everything is still available, so you can still make a button full screen

AddSense Chrome 1.2.1: active objects, dimensions, measures, link to Catwalk

A new version of my Chrome extension for Qlik Sense, Add Sense, is now available in Chrome Web Store. This is a pretty big version, actually that’s why it has number 1.2.1, because a bug sneaked into 1.2.0 which I had to fix.

New app level operations

You reach the new functions from the app popup box:

In fact, most of the buttons are new. From the left to the right they are used for:

  • showing the script
  • listing the tables
  • exploring the data model (in Catwalk)
  • listing variables
  • listing dimensions
  • listing measures
  • listing extensions used
  • listing active objects

Data model

A number of the new functions helps you with the data model. You can see what tables are defined in the app, and list dimensions and measures (and copy their definition into a program of your choice, like Excel or something). But perhaps the best new function is the link to Catwalk. Click on the compass icon, and it will open Catwalk with your current app:

If you don’t know what Catwalk is it’s time to get to know it knopw. It’s an open source tool from Qlik that helps you explore the data model of a Qlik Sense app. If it doesn’t work on your server, you might need to whitelist it. Check the documentation! Originally I planned to do some visualization of the data model, but I realized that I cannot make anything better than Catwalk, so why not reuse it.

List all active objects

The Add Sense extension uses Angular and some CSS selectors to find Qlik objects in your page, whether it’s the standard Qlik Sense client or a mashup. This only works for visualizations that are either Qlik Sense standard visualizations or extensions built with the traditional Angular-based method. But in a custom built web app using Qlik you might choose to visualize the data in some other way. Qlik Sense objects used this way have previously not been available in Add Sense, you could not check their properties, monitor recalculation times etc.

With the new function to list all active objects that has changed. While the little boxes showed on the page start from the HTML DOM and Angular scopes, this function uses enigmajs and lists all objects active in the enigmajs session. It might look something like this:

Example from the demo app ‘History of the fortune 500’

It still needs to find the enigmajs session, which might not work in all cases. If you want to use the extension for a case where it does not work, please let me know, you might be able to fix that with just a very small change.

Dimensions and measures

The extension can now also list dimensions and measures.

Dimensions

You can use the copy function in the dialog to copy the contants to the clipboard and then into application of your choice, like Excel etc.

Measures

And that’s it for the new functions. Please let me know if there is anything you are missing.

Printing Qlik Sense extensions

From time to time I get questions from Qlik customers and partners with some problem regarding Qlik Sense extensions or mashups. Usually this means a few hours of troubleshooting and hopefully fixing something, fun and interesting. Could be extensions that break when Qlik Sense is upgraded, performance issues or some feature that doesn’t work.

A recurring problem is with printing extension objects. Many customers don’t care whether this works, they don’t use NPrinting or it’s not relevant for their extensions, but some do. And if they have problems, it can be a challenge to solve them if you have never done it before.

How does it work

Qlik Sense uses snapshots for printing. That means what’s printed is not what you see on your screen, but a snapshot of the data in the extension, that is then re-rendered by the rendering engine and eventually printed. There is no live connection to the Qlik Sense engine available during this re-rendering, which means that everything that needs a live connection is not available. That’s why you should always base your rendering only on the layout.

So, a first step is to verify that the extension does not do any calls that require an engine connection in the rendering part (they can be used in the property panel, and in many cases are to fill dropdown lists with content etc). This might require some refactoring to solve and so might take some time, but in most cases this is not the problem.

Waiting for the extension to be ready

A more common problem is that the printing is made before the extension is ready. This might mean that printing works sometimes, but not all of the time. It might also mean that the printout is partial, showing the extension when parts of it are rendered, but not all of it etc.

To solve this you need to return a Promise and make sure it is not resolved until your rendering is complete, something like this:

paint: function ($element, layout) {
  // do your rendering
  return new qlik.Promise(function (resolve, reject) {
    // when rendering is complete, call resolve
    resolve();
    // optionally if rendering fails, call reject 
    reject();
  });
} //end of print function

The Promise supplied by Qlik now follows the standard javascript API (though it looks like it isn’t the standard) unlike in previuos releases where it was essentially angular $p service. I’m afraid that means the code I’ve published earlier in this blog no longer works, the code above is how it should be.

Using CSS in Qlik Sense

Whether you are building extentions in Qlik Sense or including Qlik Sense objects in a mashup you very likely will need some CSS. There are even some things you can really only do with CSS. And since Qlik released Themes support there is also the possibility of adding your own stylesheets to the Qlik Sense client with or without other changes, like extensions or mashups.

But stylesheets are different. They are not like javascript, with a defined API with methods, parameters and return values. Instead they have their own logic, with CSS selectors, specificity and interdependance. When something breaks, you won’t get error messages but things will just look wrong, not be visible at all or stop working. And very little is documented.

The qv-object rule

When you build an extension you can include CSS rules. To make it possible for you to add rules that affect only your extension Qlik Sense will add a CSS class with the format ‘qv-object-[extension]’ to the HTML element your extension is rendered in. So if your extensions qext filename is xxxx.qext, it will add the CSS class ‘qv-object-xxxx’. The idea is that you should prefix all your CSS rules with qv-object-xxx, somthing like this:

.qv-object-xxx .qv-object-content {
  overflow: auto;
}

.qv-object-xxxx ul {
  list-style: none;
}

.qv-object-xxxx .important {
  color: red;
}

If you don’t do this, your styling might affect other content in the page. Sometimes that is what you want, but for normal extensions you should not do that. You might break other stuff in the page and create bugs that are hard to find.

Extension HTML structure

The structure your extension is rendered into looks like this(this is a simplified structure):

<article class="qv-object qv-object-xxx">
  <div class="qv-inner-object">
    <header class="qv-object-header">
      <h1 class="qv-object-title">
        <h2 class="qv-object-subtitle"></h2>
      </h1>
    </header>
  </div>
  <div class="qv-object-content-container">
    <div class="qv-object-content">
      Your extension renders here
    </div>
  </div>
</article>

This means that:

  • a .qv-object-xxxx rule will affect the whole box the extension is rendered in, including title
  • a .qv-object-xxxx .qv-object-content rule will affect just the extension body, not titles etc
  • a .qv-object-xxxx .qv-object-title will affect the title and possibly the subtitle
  • hoover buttons are outside of the qv-object-xxxx element and cannot be styled based on the qv-object-xxxx class

Note that this structure is as far as I know undocumented. It has been pretty stable so far, but still might change in the future. The same structure is used for both built-in and extensions, might be good to know if you are building a mashup.

Loading your CSS

To make your CSS rules work you need to load them in the browser. They should be loaded once, even if your extension is used several times in the same page/sheet. The best place to do this is at the very start of your code, at the beginning of the callback function in the define call.

There are two ways of loading the CSS. First you could add a link to the CSS file to the HTML page. An easy way to do this is with the requirejs css plugin, like this:

define( [ "css!./style.css"], function () {
/* requirejs will add a link to the document, nothing more is needed */

You could do this yourself too, but there is really no reason to do this, and you need to be careful and handle all cases, like virtual proxies and when your extension is used in a mashup not served by Qlik Sense.

The other possibility is to add the contents of your stylesheet to a style element in the document header. That requires a bit more code:

define( ['jquery', 'text!./style.css'], function ($, cssContent ) {
    $( '<style>' ).html(cssContent).appendTo( 'head' );

You can also do it without using jQuery, with standard javascript, but that means a few more lines.

The first method, adding a link to the stylesheet, has the advantage that references to external resources, like images and fonts, works, provided that you include those files in your extension too. But if you are running the extension in a mashup on an external (not Qlik Sense) server you might run into problems, since there are security restrictions on loading CSS from other servers.

That’s why I generally use the second method, adding the stylesheet text to the document. Images referenced in the stylesheet then needs to be Base64-encoded and included in the stylesheet itself. That works well for small images, if they are not too many. But if you have many images, or need to load for example font files, you should probably go for the link method.

Who am I? Getting the user id in a Qlik Sense Extension or mashup

Sometimes you need to know who the user is in your Qlik Sense extension or mashup. Perhaps you want to help the user filling in some data, display notifications to the user or something else that I can’t even think of.

getAuthenticatedUser call

There is no property containing user id (at least not someone that I know of), you’ll need to call an API one way or the other. The relevant call in the API is getAuthenticatedUser(), available on the global object.

In an extension, you should use the global property available on the app, so the call would be app.global.getAuthenticatedUser(). In a mashup it depends.. If you need to do this before the app is opened, you could use qlik.getGlobal(config) to get the global object. But be aware that this will mean another open web socket. If you can wait, it’s better to use app.global, since that means you will reuse the existing web socket.

Like most API calls, getAuthenticatedUser() is asynchronous, so you need to call it like this:

qlik.currApp(this).global.getAuthenticatedUser().then(function(reply){
    console.log('user',reply.qReturn);
});

If you run this in Qlik Sense Desktop, you should get the string ‘Personal\Me’. But in Qlik Sense Enterprise it’s a bit more complicated. Ehen I run it I get: ‘UserDirectory=UPPER88QS; UserId=erik’. So this is a string, which contains two key-value pairs. You’ll need to parse this, to grab the UserId, or if you really want both values (perhaps you have more than one UserDirectory? Perhaps this is different between production – test – development?

Using OSUser()

But there is another method. Youd could use the Qlik Script system function OSUser(). In a mashup this is probably not a great idea, since you would need to either create a generic object containing OSUser(), or call the Evaluate method, not even included in Capabilities API, only in Enigma.

But in an extension the framework always creates a generic object for you and gets the layout. So you could add ‘OSUser’ to your initialProperties, and get the result in your layout, something like this:

initialProperties: {
   user: {
      qStringExpression: '=OSUser()'
   }
},

In most cases you would of course have other stuff in your properties too, and they can easily be combined. Don’t show this in your property panel, if you don’t want your users to be able to change it.

This will mean that you in layout.user will have the user the same way as when you called getAuthenticatedUser(), you will probably need to parse it, but you don’t have to handle the fact that is it asynchronous.

A warning

This is all client side. That means it’s not really safe, you should not use this to restrict user access – it’s OK to use this to hide operations from the user that they should not be allowed to use, but you need to verify the user serverside too, in a safe way, that can not be hacked. But that’s another topic…

Pros and cons of Qlik Sense mashups

Recently I got the question on if I would recommend using Qlik Sense mashups. That got me thinking, of course the question is not so simple: it all depends. As with most things there are pros and cons…

Why would you use Qlik Sense mashups?

There are several reasons for using Qlik Sense mashups. A very common one is that you want to apply your companys profile and have a look-and-feel more like that you have for other systems. When I started building mashups for customers Qlik Sense hade no support for theming, so if you wanted to change things like fonts you needed to do that in a mashup. Now you can do this in a theme, but I honestly don’t know how much custom themes are used today.

Another common reason is that you want navigation to work another way than it does in Qlik Sense. Perhaps put sheets in a hierarchical structure or have views targeted to different user categories.

You might also mobile support to work differently than it does in standard Qlik Sense. In a mashup you can leverage open source CSS framework like Bootstrap or Bulma which gives you possibilities you do not have in the built-in Qlik Sense client.

Another reason is to simplify the user interface. In a mashup you can focus on the workflow that’s most important for your users (usually analyse data) and skip features like edit mode, storytelling, data load and modelling. This could potentially let your users get started faster and reduce the need for training, a big cost in a large dashboard projects.

You might also want to add features not in the standard Qlik Sense client. Examples could be commenting, writeback, sharing, exports not covered in the standard client, integration with other systems. Features like alternate state and default (startup) bookmark used to fall in this category, but are now included in the standard clent.

Problems with using Qlik Sense mashups

You should realize that mashups require HTML, CSS and javascript knowledge, a skillset most Qlik developers don’t have. You need to make sure you have both web developer skills and Qlik skills in your organization, whether you have that inhouse or work with a partner. And even though there are lots of web developers out there, very few of them know how to work with the Qlik APIs.

And the javascript environment is changing fast. While Qlik script has changed little in the 12 years I have worked with Qlik, the javascript environment has changed a lot. The language has a lot of new features, and frameworks, build tools and libraries has changed even more, so that the environment used in many mashups, with angularjs 1.x, today is pretty old and completely different frameworks (React etc) dominate, at least in new projects.

The tools included with Qlik Sense, like dev-hub, the Mashup Editor and the templates included makes it easy to create a mashup with only drag-and-drop and really no programming, but for production level projects it really is not enough. You would want stuff like multi-page support (including only loading Qlik Sense objects when they are needed), version handling and a dev environment where you can use npm packages, build tools etc.

Some advice on mashup development

So, you have decided that your use case is best solved with mashups. But how should you go about developing it? Here are some advice based on my experience with building mashups.

Recognize that you need web developer skills. The mashups itself is largely a web developer project. You need experience on web development, and on troubleshooting and debugging web apps. Someone with deep knowledge of HTML, CSS, Javascript and Qlik APIs is needed.

Web developer skills is not all. For users the most important part of your mashup is the data. For that you still need Qlik developer skills. In many cases you would have two kind of developers, those building charts and those working on the mashup itself.

Use version control. I used to say that version control is what differentiate professional development from private hacks. Today this is no longer true, even many hobby projects use version control. Set it up early in your project, commit changes often, make suire you know exactly what code runs in production.

Separate Qlik Object definitions from the javascript code. Try to avoid having Qlik Sense object definitions, field names etc in the actual code. Separate object id’s etc into separate configuration files or use tags in the Qlik Sense apps. This improves reusability of your mashup code and simplifies things a lot.

Use a CSS framework. A CSS framework like Bootstrap or Bulma helps you a lot with making your mashup responsive and good-looking. You might want to modify it by overriding the styles with your profile colors, fonts etc, but add those later.

Files in Qlik Sense extensions

Qlik Sense allows you to add extensions to your installation. In a server environment you do this by importing a zip file, containing one or several extensions. In Qlik Sense Desktop you can unzip (the same) zip file to a directory under Documents/Qlik/Sense/Extensions.

The qext file

The qext file is what defines the extension. It’s a JSON file, it has to be valid JSON, but very few properties are mandatory. The qext file defines the extension root, Qlik Sense will make files the directory where the qext file and all directories under it available for HTTP calls to the server. So if you add an extension with the file xxxx.qext, you can fetch the file from the server with:

HTTP GET /extensions/xxxx/xxxx.qext

And all other files in the extension can also be fetched the same way:

HTTP GET /extensions/xxxx/xxxx.js

Sub-directories can also be used:

HTTP GET /extensions/xxxx/lib/jquery.js

Not that the directory name on disk is not relevant. On Qlik Sense Desktop you can build your own directory structure. Extensions in Dashbord bundle and Visualization bundle are kept in their own sub-directory, which doesn’t affect the URL used to load them. But if you do build a structure for your extensions, be careful that you do not keep duplicates of the same extensions. If you do you will not know which copy is actually loaded.

Multiple qext files

You can also have multiple qext files in the same zip file, which will mean that several extensions, and their files, are made available. Qlik Sense Enterprise will not allow you to have more than one qext file in the same directory, you can do this in Qlik Sense Desktop, but it is confusing, so you probably shouldn’t.

Multiple qext files is useful when you want to use the same files in more than one extension, like some library, CSS files etc. You can then put common files in one directory and add a qext file in it to make it available for all extensions. By putting them in the same zip file you make sure that they are updated at the same time as the extensions using the library. Another effect is that if the user is using two different extensions that use the same library, files will only be downloaded once. If every extension has it’s own copy of a library, it will be downloaded multiple times.

For Qlik Sense Enterprise you have no control over how the extension files are stored. It is not hard to find the files on disk, but the repository is responsible for storing them and serving to the client.

The extension type

One of the fields you always should have in the qext file is the type. In a visualization extension, that you should be able to use in the Qlik Sense client, it should be set to ‘visualization’:

"type": "visualization",

If you set it to something else, the Qlik Sense client will not load it and your users will not be able to create visualizations using it.

For mashups it is usually set to ‘mashup’:

"type": "mashup",    

This is not absolutely necessary, your mashup will still work even if you set the type to something else, but if you want to manage it and possibly edit the file in Qlik Sense dev-hub you need to set the type to ‘mashup’. That also means that if you want to hide your mashup in dev-hub, set the type to something else (perhaps ‘webapp’ ?).

There are also a few other types used by Qlik Sense: ‘visualization-template’ and ‘mashup-template’. These types are used for the templates used in dev-hub when you create a new visualization or mashup.

If you plan to build several mashups creating a good mashup template with the look-and-feel you want might be a good choice.

The wbfolder.wbl file

One of the most misunderstood file in extensions is the wbfolder.wbl file. It is simply a list of files in the extension, with one line for every file, terminated by semicolon:

com-qliktech-horizlist.js;
com-qliktech-horizlist.qext;
horizlist.css;

The wbfolder.wbl file is not mandatory. It is not needed for your extension for work, if you do have one it does not need to contain all files. It is only used by the dev-hub editors. Without it you cannot open or duplicate the extension in dev-hub.

If you do have it, only the files listed in wbfolder.wbl will be available in the editors. Also only the files in wbfolder.wbl will be copied if you make a copy of the extension or mashup. The other files will stil be available over HTTP, Qlik Sense will serve them.

A scenario I have seen used, is that a web developer buiilds a mashup, but then users (super-users ??) can modify files in it, like HTML, CSS or configuration files. In that case you can add a wbfolder.wbl to the extension containing just the files users should be able modify, but not other stuff, like libraries, possibly some JavaScript etc.