Qlik nebula.js – first test drive

Qlik recently has released quite a lot of open source software. One of the more interesting of those is nebulajs, described as ‘Product and framework agnostic integration APIs for Qlik’s Associative Engine’.

Nebulajs has three parts:

  • supernova: A component model for Qlik Sense visualizations
  • nucleus: A framework for injecting supernova’s into HTML pages
  • cli: a command line interface for developing supernova’s

This somewhat resembles the current Qlik Sense model, where supernova’s have the same role as extensions, while nucleus replaces the mashup API.

My aim for this test drive is to try the supernova part by building a simple supernova, or visualization. The mashup part will have to wait for later.

Installation and setup

To use nebulajs you need nodejs version 8.0.0 or later and access to Qlik engine. Since I’ll be doing this on Windows, I will use Qlik Sense Desktop, which I have already installed. I also have the right version of nodejs, so I can install nebulajs globally and create my first project:

cd \src\nebula-test
npm install @nebula.js/cli@next -g
nebula create nova-table

When asked about picassojs template I select ‘none’ we will save picasso for another time. This will create a project for me. The project comes with build script configured to use modern javascript tools like babel and webpack.

The default for nebulajs projects is using Qlik Sense Docker, but I will be using Qlik Sense desktop, which means I have to add the Qlik Sense Desktop port number in package.json, under scripts:

"start": "nebula serve --enigma.port 4848",

Now we can start our project:

cd nova-table
npm run start

And a browser window will open with a listing of your Qlik Sense Desktop apps. Select one (I’m in the habit of using the demo app Consumer Sales, but almost anyone will do) and you will get a page with a selection bar at the top and your new supernova displayed in the middle of the screen:

Supernova starting point

Add some functionality

You find the source code of your new supernova in the src directory. Start with the file index.js, which is kind of the main program of your supernova. The component has six methods – to get something working we’ll start with two of them.

The mounted method is where you get the reference to your HTML element. Unlike in the current extension API you will get a plain HTML element, not a jQuery wrapper around it – remember supernova is platform agnostic. The default implementation just sets the content to Hello! – we’ll change that so that we keep a reference to the element (we’ll need that later) and set the content to ‘nova-table’ so that we know that our supernova is running (we’ll soon overwrite this).

mounted(element) {
   this.element = element;
   this.element.innerHTML = 'nova-table';
}

Next up is the render method, which plays the same role as the paint method in todays extension api. But parameters have changed: we do not get the element at this stage, that’s why we need to save it in mounted, and we get a second parameter, called context. While this feels like a good idea, there is not much inside the context yet, so we won’t use it yet. Instead we just add the layout to the element for now, so we can see what we have got:

render({
    layout,
    context,
}) {
    this.element.innerHTML = JSON.stringify(layout);
    console.log('render', this, layout, context);
}

Add a hypercube to get some data

Next step is to add a hypercube to get some data into your supernove. To do this we need to edit object-properties.js and add a hypercube definition:

qHyperCubeDef: {
    qDimensions: [],
    qMeasures: [],
    qInitialDataFetch: [{
      qWidth: 10,
      qHeight: 50,
    }],
  },

When you have done this your supernova will have a hypercube, which you can see in the display, but it will be empty. In Qlik Sense we would use the property panel to add some dimensions and measures, but there is no property panel yet in nebulajs. We will have to edit the properties by hand. If you click the ‘Props’ button you will get the properties (including the empty hypercube definition). Add a dimension to the dimensions array, something like this:

{"qDef":{"qFieldDefs":["Invoice Number"]}}

Note that this is JSON format, so you need to enclose qDef and qFieldDefs in “. When you’ve done this, you will get a hypercube with contents, and it will look something like this:

Obviously it’s time to implement the rendering.

Basic rendering

For this test drive we will just generate some basic HTML from the hypercube data. The framework supports, even forces you to (in it’s standard setup) to use modern javascript with templates etc. That means we can generate a simple HTML table with just a few lines of code, like this:

render({
        layout,
        context,
      }) {
        const hypercube = layout.qHyperCube;
        let html = '<table><thead><tr>';
        html += hypercube.qDimensionInfo.map(d => `<th>${d.qFallbackTitle}</th>`).join('');
        html += hypercube.qMeasureInfo.map(m => `<th>${m.qFallbackTitle}</th>`).join('');
        html += '</tr></thead><tbody>';
        html += hypercube.qDataPages[0].qMatrix.map(row => `<tr>${row.map(cell => `<td>${cell.qText}</td>`).join('')}</tr>`).join('');
        html += '</tbody></table>';
        this.element.innerHTML = html;
}

If this looks strange to you, you need to catch up with javascript features like template literals, arrow functions, Array.map and Array.join.

Now just add dimensions and measures to your properties:


"qDimensions": [{"qDef": {"qFieldDefs": ["Customer"] }}],
"qMeasures": [{"qDef":{"qDef":"Sum([Sales Amount])"}}]

And you will get a simple HTML table:

Working, but not something you would use. Let’s make it a bit better with some CSS.

Add some styling

As you might have noticed in the code, requirejs is no longer used, instead you use the import statement. That works for javascript files, but you can actually use it for css files. So we can simply add this line to our index.js:

import './style.css';

We also need a class for our root element, to make sure our styling does not affect other visualizations or the framwork. I’ve called this class ‘nova-table’ (as the extension) and added a root div with this class to the rendering code. And finally I have made sure that numeric fields get the css class ‘numeric’. These are the affected rows:

let html = '<div class="nova-table"><table><thead><tr>';
....
html += hypercube.qDataPages[0].qMatrix.map(row => `<tr>${row.map(cell => `<td${cell.qNum === 'NaN' ? '' : ' class="numeric"'}>${cell.qText}</td>`).join('')}</tr>`).join('');
html += '</tbody></table></div>';   
        

And add a css file (style.css) where I set up some basic styling:

.nova-table {
    font-family: "Source Sans Pro", "Segoe UI", "Helvetica Neue", -apple-system, Arial, sans-serif;
    height: 100%;
    overflow: auto;
}

.nova-table table td,
.nova-table table th {
    text-align: left;
}
.nova-table table td.numeric {
    text-align: right;
}

This gives us something like this:

Conclusion

Qlik nebulajs is a big step forward with it’s support for a modern javascript development environment and good key concepts. If you plan to work on Qlik visualizations in the future it’s definitely worth taking a look at. You can relatively easily get something up and running even though the framework is far from ready.

You find my test project here

Building on Qlik Sense bundled extensions

From the very start when Qlik Sense was launched a recurring question has been ‘how do I modify the xxxx chart and add feature yyyy’. That has never been supported and still isn’t. But with the visualizations provided by Qlik as in the extension bundles it’s another thing. These visualizations are bundled with the installation, but Qlik has also published the source at github.com/qlik-oss, and adding features to those are possible, even encouraged.

The multi-kpi extension

One of the extensions in the visualization bundle is the multi-kpi extension, originally written by Alexander Nerush and published under the very modest name SimpleKPI. Qlik has forked the repository, made some changes, written a few pages of help info and bundled it with Qlik Sense.

The original name SimpleKPI is pretty misleading: this is a powerful KPI object with lots of options and functionality many customers want. I encourage you to take a look at it if you haven’t already.

The requirement

One of these options is the possiblity to connect a sheet to the KPI, so that when the user clicks on the KPI, a sheet showing details behind that number opens. But sometimes you do not only want a sheet to open, but also some selections to be applied. So we want the possibility to connect not only a sheet, but also a bookmark to the KPI.

Adding this to the built-in KPI object is not possible, since you cannot modify it. Writing your own KPI object from scratch is of course possible, but would take some time (certainly if you want the features of the multi-kpi object), but adding it to the multi-kpi object is much easier.

Making the addition

To make the addition you do the following:

  • make a fork of the multi-kpi repository
  • run npm install to get the dependencies needed
  • make your changes to the source code
  • build and test like with any extension

My version of multi-kpi, with the link to bookmark feature is available here. If you feel your feature is of general interest, you might also create a pull request back to Qlik’s version, and let them decide if it’s something worth adding.

Add Sense Chrome 1.1.0: properties as patches, enable copy

Version 1.1.0 of my Add Sense Chrome Extension is now available in Chrome web store. This releas has two new features, one of which is pretty experimental.

Properties in patch mode

Properties in patch mode

From the beginning the extension has allowed you to see properties as an object, that includes all properties. But sometimes you need properties in patch format, with the path to each property and the value. This is the format used in one of the most powerful API calls of the QIX Engine, the applyPatches call.

The list of patches you will see:

  • includes all properties
  • is sorted
  • and can be filtered

Creating the paths for applyPatches calls is one use for it. Another is when you want to for example compare propertries of two objects, like the expressions used (are they the same??) or dimensions. In that case simply open properties for both objects, switch to patch mode and filter on what you are interested in.

Enable copy

Quite frequently you want to copy something from Qlik Sene and paste into a document or another program. This is hard to do. The Enable copy alternative helps you with that by simply turning on standard HTML text select. You can then select and copy text much like in a standard HTML page.

This works well in some cases, but in other it conflicts with the Qlik Sense UI and does not work at all, might even make some stuff unusable. So use it with care and do not have too high expectations.