Skip to content

Apply bookmarks (Platform SDK)

qlik/api: The typescript platform SDK used in this tutorial has been deprecated. Review how to transition to qlik/api.

Introduction

In this tutorial, you are going to learn how to apply a bookmark in a Qlik Sense application programmatically and list out the current selected fields and values with the Platform SDK.

Requirements

Variables you need to complete this tutorial

  • host: The hostname for your Qlik Cloud tenant (for example hello.us.qlikcloud.com)
  • clientId: The clientId for the machine-to-machine OAuth client
  • clientSecret: The clientSecret for the machine-to-machine OAuth client
  • appId The appId is the unique identifier (guid) for the application you want to connect to.

Authorize a connection to Qlik Cloud

Configure a Nodejs application and add the @qlik/sdk package using NPM.

npm install @qlik/sdk

Create a file named bookmark-apply.js file of your application you want to use the sdk, import the Qlik and AuthType modules from the sdk.

const Qlik = require('@qlik/sdk').default;
const { AuthType } = require("@qlik/sdk");

Update the configuration values with the variables identified earlier in the tutorial.

const host = process.env['host'] // "<tenant.region.qlikcloud.com>";
const clientId = process.env['clientId'] // "<OAUTH_CLIENT_ID>";
const clientSecret = process.env['clientSecret'] //"<OAUTH_CLIENT_SECRET>";
const appId = process.env['appId'] // "<APPID_GUID_LIKE_THIS_b1b79fcd-e500-491c-b6e9-2ceaa109214c";

Configure authorization to Qlik. This example uses a machine-to-machine OAuth token to connect to Qlik Cloud.

const config =  {
  authType: AuthType.OAuth2,
  host: host,
  clientId: clientId,
  clientSecret: clientSecret
};

Apply a bookmark

Begin with an async function to immediately execute this snippet. The remainder of the code goes in between the curly {} braces.

(async () => {})();

Establish a connection to your Qlik Cloud tenant.

  const qlik = new Qlik(config);
  await qlik.auth.authorize();

Get a reference to the Qlik Sense application to open and open it.

  const app = await qlik.apps.get(appId);
  await app.open();

Add the objectId for the bookmark you want to apply into the app.applyBookmark function. An objectId for the sample application referenced in the Requirements section has been entered so you don’t have to look it up.

  const bmk = await app.applyBookmark('SmDXrz');

Once the bookmark is applied, create a session object to query the current selections from the app.

  const sessObj = await app.createSessionObject({
      "qInfo": {
        "qType": "CurrentSelections"
      },
      "qSelectionObjectDef": {}
    }
  );

  • qType: Use CurrentSelections to identify what kind of session object to create.
  • qSelectionObjectDef: This property instructs the session object to use the selection object schema to format the data returned in the object.

Get the layout of the current selections session object.

  const selectionLayout = await sessObj.getLayout();

The current selections layout is a JSON object with the following structure and information. To get the fields representing the current selection, look for the qSelections property in the output.
GenericObjectLayout {
  qExtendsId: undefined,
  qHasSoftPatches: undefined,
  qInfo: NxInfo {
    qId: '1aa4a8ec-1d03-4cd5-8c31-eb7a372567d3',
    qType: 'CurrentSelections'
  },
  qMeta: NxMeta {
    qName: undefined,
    privileges: [ 'read', 'update', 'delete' ]
  },
  qSelectionInfo: NxSelectionInfo {
    qInSelections: undefined,
    qMadeSelections: undefined
  },
  qStateName: undefined,
  qListObject: ListObject {
    qDimensionInfo: NxDimensionInfo {
      qApprMaxGlyphCount: undefined,
      qCalcCondMsg: undefined,
      qCardinal: undefined,
      qCardinalities: [NxCardinalities],
      qContinuousAxes: undefined,
      qDerivedField: undefined,
      qDimensionType: undefined,
      qFallbackTitle: undefined,
      qGroupFallbackTitles: undefined,
      qGroupFieldDefs: undefined,
      qGroupPos: undefined,
      qGrouping: undefined,
      qIsAutoFormat: undefined,
      qIsCalculated: undefined,
      qIsCyclic: undefined,
      qIsOneAndOnlyOne: undefined,
      qIsSemantic: undefined,
      qLibraryId: undefined,
      qLocked: undefined,
      qMax: undefined,
      qMin: undefined,
      qNumFormat: [FieldAttributes],
      qReverseSort: undefined,
      qSortIndicator: undefined,
      qTags: undefined
    },
    qStateName: undefined
  },
  qNxLibraryMeasure: NxLibraryMeasure {
    qActiveExpression: undefined,
    qDef: undefined,
    qExpressions: undefined,
    qGrouping: undefined,
    qLabel: undefined,
    qLabelExpression: undefined,
    qNumFormat: FieldAttributes {
      qnDec: 10,
      qDec: undefined,
      qFmt: undefined,
      qThou: undefined,
      qType: 'UNKNOWN',
      qUseThou: undefined
    }
  },
  qSelectionObject: SelectionObject {
    qBackCount: 1,
    qForwardCount: 0,
    qSelections: [ [NxCurrentSelectionItem], [NxCurrentSelectionItem] ],
    qStateName: undefined
  }
}

To get the list of selected field values, you are going to create a list object based on the field names present in the qSelections array. A helper function named getListObject accepts arguments including the app reference, the field name, and the number of selected items in the field to retrieve the list of selected field values.

First, loop through the qSelections array to get the field names and access to the selected field values.

  for (const item of selectionLayout.qSelectionObject.qSelections)
    {
    console.log(item.qField);
    console.log("==========");
    const myListObj = await getListObject(app, item.qSelectedCount, item.qField);
    const listLayout = await myListObj.getLayout();
    for (const pages of listLayout.qListObject.qDataPages)
      {
        let selVals = await pages.qMatrix.filter(item => item[0].qState == 'S');
        for (const val of selVals)
          {
            console.log(val[0].qText);
          }
      }
    console.log("==========");
    }
  process.exit();

Observe the myListObj constant. It is making a request to a helper function in this snippet called getListObject.

    const myListObj = await getListObject(app, item.qSelectedCount, item.qField);

This function is needed in order for the code snippet to work properly. Add the getListObject function to your script file as a separate async function outside the main function you’ve been working in.

async function getListObject(app, valCount, fieldName)
{
  const listObj = await app.createSessionObject({
    "qInfo": {
        "qId": "LB01",
        "qType": "ListObject"
      },
      "qListObjectDef": {
        "qStateName": "$",
        "qLibraryId": "",
        "qDef": {
          "qFieldDefs": [
            fieldName
          ],
          "qFieldLabels": [
            fieldName
          ],
          "qSortCriterias": [
            {
              "qSortByLoadOrder": 1
            }
          ]
        },
        "qInitialDataFetch": [
          {
            "qTop": 0,
            "qHeight": valCount,
            "qLeft": 0,
            "qWidth": 1
          }
        ]
      }
  });
  return listObj;
}

With the list object defined and returned, get the layout of the session object containing the field values of the selected field.

    const listLayout = await myListObj.getLayout();

Loop through qDataPages array and filter the qMatrix child array to get the current selected field values by returning values with a qState='S'. The 'S' qState indicates a selected field value in the array.

    for (const pages of listLayout.qListObject.qDataPages)
      {
        let selVals = await pages.qMatrix.filter(item => item[0].qState == 'S');
        for (const val of selVals)
          {
            console.log(val[0].qText);
          }
      }
    console.log("==========");
    }
  process.exit();

Next steps

Now you know the basics of working with bookmarks programmatically using the Qlik Platform SDK. Head up to the top of qlik.dev to learn more about how you can embed analytics into your applications and bring insight right to where your end users work.

Full code snippet

//bookmark-apply.js
//Apply a shared bookmark in an app and print out the selected values.
//Authorizes through OAuth2 M2M to connect to a Qlik Cloud application.
//To create an OAuth client for this snippet, go here:
//https://qlik.dev/authenticate/oauth/create/create/create-oauth-client
//To use a sample app with this snippet, download and import the executive
//dashboard from this github location https://github.com/qlik-oss/qlik-cloud-examples/raw/main/qlik.dev/sample-apps/qlik-dev-exec-dashboard.qvf
/*PARAMS
* host: the hostname of your tenant
* clientId: the clientId of the OAuth2 client you created
* clientSecret: the client secret for the OAuth2 client you created
* appId: The GUID for the Qlik Sense app
*/

//Uncomment below if you're using this code with https://repl.it
//global.fetch = require('@replit/node-fetch');

const Qlik = require('@qlik/sdk').default;
const { AuthType } = require("@qlik/sdk");

//config-values
const host = process.env['host'] // "<tenant.region.qlikcloud.com>";
const clientId = process.env['clientId'] // "<OAUTH_CLIENT_ID>";
const clientSecret = process.env['clientSecret'] //"<OAUTH_CLIENT_SECRET>";
const appId = process.env['appId'] // "<APPID_GUID_LIKE_THIS_b1b79fcd-e500-491c-b6e9-2ceaa109214c";

const config =  {
  authType: AuthType.OAuth2,
  host: host,
  clientId: clientId,
  clientSecret: clientSecret
};

(async () => {
  const qlik = new Qlik(config);
  await qlik.auth.authorize();
  const app = await qlik.apps.get(appId);
  await app.open();
  const bmk = await app.applyBookmark('SmDXrz');
  if(!bmk)
  {
    console.log("bookmark apply failed.");
    process.exit();
  }

  const sessObj = await app.createSessionObject({
      "qInfo": {
        "qType": "CurrentSelections"
      },
      "qSelectionObjectDef": {}
    }
  );
  const selectionLayout = await sessObj.getLayout();
  for (const item of selectionLayout.qSelectionObject.qSelections)
    {
    console.log(item.qField);
    console.log("==========");
    const myListObj = await getListObject(app, item.qSelectedCount, item.qField);
    const listLayout = await myListObj.getLayout();
    for (const pages of listLayout.qListObject.qDataPages)
      {
        let selVals = await pages.qMatrix.filter(item => item[0].qState == 'S');
        for (const val of selVals)
          {
            console.log(val[0].qText);
          }
      }
    console.log("==========");
    }
  process.exit();
})();

async function getListObject(app, valCount, fieldName)
{
  const listObj = await app.createSessionObject({
    "qInfo": {
        "qId": "LB01",
        "qType": "ListObject"
      },
      "qListObjectDef": {
        "qStateName": "$",
        "qLibraryId": "",
        "qDef": {
          "qFieldDefs": [
            fieldName
          ],
          "qFieldLabels": [
            fieldName
          ],
          "qSortCriterias": [
            {
              "qSortByLoadOrder": 1
            }
          ]
        },
        "qInitialDataFetch": [
          {
            "qTop": 0,
            "qHeight": valCount,
            "qLeft": 0,
            "qWidth": 1
          }
        ]
      }
  });
  return listObj;
}

Was this page helpful?