Unlock a world of possibilities! Login now and discover the exclusive benefits awaiting you.
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).
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.
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).
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
// 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
// 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;
// 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.
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)
})
})
})
})
})
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.