Qlik Community

Qlik Design Blog

All about product and Qlik solutions: scripting, data modeling, visual design, extensions, best practices, etc.

Announcements
QlikWorld, June 24-25, 2020. Free virtual event for DI and DA gurus. Register Now
Employee
Employee

Introduction

We've covered on this blog about how to get started with the Qlik APIs and some of the associated tools like Enigma.js.But what if you're completely new to Qlik Sense and feel more comfortable developing websites and building visualizations? You're probably thinking: "Do I really have to learn something else? Just get me started!" Well this is what we'll try to do here - give web developers familiar with modern web development (e.g. React, Webpack, ES6+) an approachable tutorial to connect to Qlik Sense, understand the layout of the app, and get some data within 20 minutes!
Before we get started, we will assume that you have some knowledge of web development as well as access to a Qlik Sense server and a pre-existing app. To follow along, take a look at this repo on GitHub and download the Consumer Goods Sales app from our Demo Site.

Project Setup

Our first step will be to clone the example repo for the basic setup of the project. In this tutorial, we have already installed the development dependencies (Webpack, Webpack Dev Server, Babel) as well as the dependencies for the app (React, ReactDOM, Enigma.js). You are probably familiar with React and ReactDOM but probably not Enigma.js which is what we'll use to connect to and interact with the Qlik Engine JSON API. Enigma.js allows us to easily use all the methods that we need in simple JavaScript.

To get started, simply clone the repo, install the dependencies, and then we'll get going.

 

 

git clone https://github.com/qlik-demo-team/qlik-engine-tutorial my-qlik-app
cd my-qlik-app
npm install
npm run dev

 

 

Go to http://localhost:8080 to see "My Amazing Qlik Sense Mashup!" on your screen. Note: to see the final result of any one section, you can switch to one of five branches in the repo: start (setup), connection (connecting to Qlik Sense), hypercube (getting data), list-object (making a selection), finished (completed project).

Connecting to Qlik Sense

One of the first steps in building a web app with access to Qlik Sense is to get the domain for your Qlik Sense server as well as your app ID. Going to your Qlik Sense Hub is an easy way to get the domain. You can ignore the "https://" and just get the url of the Qlik Server (e.g. qlik-server.example.com) or if just running locally (localhost).
Qlik-Domain.png
Next you'll need the app ID of the app that you want
to access from your website. A simple way to do that is to just open the app and then look at the
URL - the app ID is right in that url after "/sense/app/[appID]/" (your URL will probably not have the "windows" before "sense").
App-URL.png
Now that we have the domain and app ID, we can connect to Qlik Sense. We'll show the code first and then explain what we're doing. Copy and paste the code below into the Home.js file and update it with the domain of your Qlik server and app ID.

 

 

const enigma = require('enigma.js');
const schema = require('enigma.js/schemas/12.170.2.json');
const SenseUtilities = require('enigma.js/sense-utilities');

const config = {
  host: '', // <== Qlik server domain here
  secure: true,
  port: 443,
  prefix: '',
  appId: '', // <== app ID here
};
const url = SenseUtilities.buildUrl(config);

const qDocPromise = enigma.create({ schema, url }).open().then(global => global.openDoc(config.appId));
console.log(qDocPromise)

 

 

Enigma.js is a Promise-based library so as you'll notice, in your console, it says Promise {<pending>} meaning it has just logged the Promise itself, not the object. Establishing the connection is a great first step in understanding how Enigma works and how we'll be communicating with our Qlik server.

Because everything is Promise-based, to actually see the returned value, we'll need an extra bit of code:

 

 

qDocPromise.then((doc) => {
  console.log(doc);
})

 

 

The resulting object is what we'll use to do most of the talking to the Qlik Sense server. Without going into much further detail, this object is called the "Doc" (in older versions, it was called the App but is now usually just called the Doc).

Listing the Available Fields

Now that we have made our connection to the Qlik server and opened the correct app, let's get a better understanding of the data by listing out the fields:

 

 

qDocPromise.then((doc) => {
  console.log(doc);

  doc.createSessionObject({ qInfo: { qType: 'fields' }, qFieldListDef: {}}).then((fields) => fields.getLayout().then((layout) => {
    const { qItems } = layout.qFieldList;
    const sorted = qItems.sort((a,b) => a.qName > b.qName ? 1 : -1)
    console.log(sorted)
  }))
})

 

 

If you open your console, you can see that the resulting array has of over 200 fields. Building a mashup without understanding anything about the data is difficult but the above snippet does a good job of just listing all the fields

available to you. But because this is an introductory exercise, we're going to pick a couple fields that we know beforehand and see if we can get some data!
 

Getting Data

Getting started with the Qlik APIs is difficult if you are not familiar with the jargon. In the Qlik Engine JSON API documentation, you'll see terms like "hypercube", "dimension", and "measure" thrown around a good bit. A hypercube is just the code that requests the data you want. Some Qlik apps can be quite large with hundreds of fields and we obviously won't use ALL of that data in every visualization. A hypercube allows us to pick only what we want. A hypercube is comprised of dimensions (typically a category in your data, e.g. "customer", "product", etc.) and measures (typically some value on which you can make calculations, e.g. sum, count, average, etc.). Copy the code below into a new file called hypercube.js:

 

 

// hypercube.js
const hypercube = {
  qInfo: { qId: 'Consumer Sales', qType: 'data' },
  qHyperCubeDef: {
    qDimensions: [ 
      { qDef: { qFieldDefs: ['[Product Group Desc]']}, qFieldLabels: ['Product Group'] }
    ],
    qMeasures: [
      { qDef: { qDef: '=SUM([Sales Margin Amount])/SUM([Sales Amount])', qLabel: 'Margin' }},
    ],
    qInitialDataFetch: [{
      qTop: 0, qLeft: 0, qWidth: 10, qHeight: 1000,
    }],
    qInterColumnSortOrder: [],
    qSuppressZero: true,
    qSuppressMissing: true,
  }
}

export default hypercube;

 

 

Now that we have our hypercube, let's use our doc object to get the data. First import the hypercube at the top of the file, just below your Enigma imports, and then add the following code:

 

 

// Enigma.js imports
import hypercube from './hypercube';

// CODE

qDocPromise.then((doc) => {
  // new code
  doc.createSessionObject(hypercube).then((obj) => obj.getLayout().then(layout => {
    console.log(layout);
    const dataPages = layout.qHyperCube.qDataPages[0].qMatrix
    console.log(dataPages)
  }))
})

 

 

Boom! And just like that, we now have some data! In your console, you'll be able to see both the layout object as well as the data. For some users, this is good enough - if you know the fields you want, you can make as many hypercubes as you'd like to get the data you're looking for. From here, you can use vanilla JavaScript to clean-up

the array to feed into a visualization library like D3 or use Picasso.js which has a plugin that can work with hypercubes.

Making a Selection

By this point, we have made our connection to Qlik Sense, we've written our first hypercube, and we've actually gotten some data. But how do we make selections? One of Qlik's key selling points is being able to interact with the data and make selections. To do that, we'll use another important object in the Qlik Engine called a List Object. List Objects, unlike hypercubes, only have one dimension and no measures. They aren't designed to give you data but rather give you information on a particular dimension. Let's dig into the example. First, create a new file called listObject.js:

 

 

// listObject.js
const listObject = {
  title: "A list object",
  description: "Description of the list object",
  qInfo: { qId: 'Consumer Sales List Object', qType: 'List Object'},
  qListObjectDef: {
    qStateName: "$",
    qDef: { qFieldDefs:  ['[Product Group Desc]'], qFieldLabels: ["Product Description"], qSortCriterias: [{qSortByLoadOrder: 1}]},
    qInitialDataFetch: [{
      qTop: 0, qLeft: 0, qWidth: 10, qHeight: 1000,
    }],
  },
}

export default listObject;

 

 

Import your list object at the top of the page. Then, inside the qDocPromise, right below the code to fetch the hypercube data, copy and paste the following:

 

 

// top of page, below other import statements
import listObject from './listObject';

// CODE

qDocPromise.then((doc) => {
  // Getting data from hypercube
  doc.createSessionObject(hypercube).then((obj) => obj.getLayout().then(layout => {
    console.log(layout);
    const dataPages = layout.qHyperCube.qDataPages[0].qMatrix
    console.log(dataPages)
  }))
  // NEW CODE: List Object
  doc.createSessionObject(listObject).then((obj) => {
    obj.getListObjectData('/qListObjectDef',[ {qLeft: 0, qTop: 0, qWidth: 10, qHeight: 100}]).then(objectData => {
      console.log(objectData);
    })
  })
})

 

 

If we open our console and peak inside objectData, we see that inside the qMatrix property, there is an array with 17 items. Each item is an array with a single object that represents a possible value for the field of "Product Group Desc". There is a descriptor/title/name for that field (qText), a numeric value (qNum), an element number (qElemNumber), and it's selection state (qState). Let's try making a selection. Just for fun, let's pick "Beverages", which as we can see in the picture below has a qElemNumber of 2.

ListObject-no_selections.png
 
Now, update the code like this:

 

 

qDocPromise.then((doc) => {
  // Getting data from hypercube
  doc.createSessionObject(hypercube).then((obj) => obj.getLayout().then(layout => {
    console.log(layout);
    const dataPages = layout.qHyperCube.qDataPages[0].qMatrix
    console.log(dataPages)
  }))
  // UPDATED CODE: List Object
  doc.createSessionObject(listObject).then((obj) => {
    obj.getListObjectData('/qListObjectDef',[ {qLeft: 0, qTop: 0, qWidth: 10, qHeight: 100}]).then(objectData => {
      console.log(objectData);
      obj.selectListObjectValues('/qListObjectDef', [2], true, false).then((res) => {
        console.log(res);
        obj.getListObjectData('/qListObjectDef',[ {qLeft: 0, qTop: 0, qWidth: 10, qHeight: 100}]).then(objectData2 => {
          console.log(objectData2)
        })
      })
    })
  })
})

 

 

Here is a quick rundown of what's happening. The doc.createSessionObject() creates our list object. We then use the resulting list object (which I've called `obj`) to call obj.getListObjectData(). When we logged that to the console, we saw that there was an array of 17 items, all of them with the name of the field and a qState of "O". We then called obj.selectListObjectValues() and selected "Beverages" which had a qElemNumber of 2 (we need to use qElemNumbers to tell the Qlik Engine which item to select). The log of "true" tells us that it was successful. We then call obj.getListObjectData() again to see that the list has been updated. There are still 17 items in the array but now we see that everything except "Beverages" has a qState of "X" while Beverages has a qState of "S". Selecting a value in this way is akin to clicking on a particular bar in a Qlik bar chart - you are selecting "Beverages" and now all the charts in Qlik Sense will, if they are connected to the column "Product Group Desc", show only the data for "Beverages". Here is the console output just to confirm our selections:
 
ListObject-selections.png

Conclusion

So there it is, you've done it! You've learned the three most fundamental tasks in creating a Qlik Sense mashup:
  • Connecting to Qlik Sense
  • Creating a Hypercube and Getting Data
  • Creating a List Object and Making a Selection
With those three skills, you'll be able to make an interactive web app with your Qlik Data. In this tutorial, we scraped the surface of all that you can do with the Qlik Engine JSON API but we hope that you can now feel free to explore a bit. Here are a few resources that we think will help you get up-to-speed with the Qlik APIs:
Labels