Sometimes during the development of your extension you have the requirement where you need to save the state of your app (layout and selections included), which afterwards you would like to restore using some UI elements (e.g. button, link…). A classical example could be the creation of annotations and comments to your filtered data points.

How we can achieve it?
The easiest solution is to create custom bookmarks. This kind of bookmarks are not visible in the standard Qliksense user interface under the Bookmarks List, indeed they are available only for the purpose they are created for.

What are bookmarks?
Bookmarks are created to save selections and a particular location. The bookmarks can later on be opened to restore the selections to a former state.

How we can programmatically create bookmarks?
The easiest way is to use the qlik.app.bookmark.create Method in the Capability API. That will create a bookmark for you, much like a bookmark created by the user in the client. But in our case we would like to create an own type of bookmarks, which are not visible in the Qliksense Client. So they way to go is to use the Engine Api. That gives us more control over the bookmark, like we can set the ID and the type ourself. In our example we are going to use the Enigma library to achieve our mission. The alternative would to go for the Engine API itself.

What is Enigma?
Enigma creates a javascript wrapper around the Qlik Engine Api, a wrapper that includes all methods defined in the version of QIX your system is using. Qlik actually has open-sourced enigmajs, you can read more, and download it from the Github repository. It is a client library that communicates with Qlik Sense backend services. It can be used in a browser or in a Node.js environment. You can use enigma.js as an SDK or do CRUD (that is create, read, update and delete) operations on apps and on app entities. You can also use it to build your own client or to build your own Node.js service. enigma.js can be used with both Qlik Sense and Qlik Sense Desktop and it is based on Promises. A Promise is an object that represents a value which might not yet exist. We can set callbacks on it, which will be invoked when the value is ready to be read.

Important: Enigma.js is still flagged as experimental in the current release. Which means that details in the implementation might change, you should be aware of that.

So, now Coding Time!
We will setup a little extension which is repsonsible for state management using the Bookmark functionality. We will store all our created bookmarks in the Local Storage of the browser, you could use any another backend service to persist your bookmarks permanently. Actually bookmarks are already persisted in your app, so this step would be not necessary, but you will have the case where you want to store additional information (not only bookmark data) of your extension, depending on your usecase, in a central repository (e.g. relational database). For the state management we will build a html table with the necessary columns (id, type, creation date and the Apply button column which fires the ApplyBookmark method). Additionaly we will have a Create Button and Clear Button (removes all created Bookmark from the html table and from the app) to allow to perform the different Bookmark operations.

As I said before we are going to use Enigma which is already included in the client. So there is no needed to explicitly import the enigma.js library in our extension, we just have to set the reference to the enigmaModel like shown below:

function(qlik, $, config, style) {

    _this = this;

    var global = qlik.getGlobal();
    var app = qlik.currApp(_this);
    var enigmaModel = app.model.enigmaModel;

We are going to use the following methods to achieve what you would like to do:

The important part by creating a bookmark is that we have to pass the necessary parameter to our method:

Name Description Type
qId Identifier of the object. If the chosen identifier is already in use, the engine automatically sets another one. This parameter is optional. If an identifier is not set, the engine automatically sets one. String
qType Type of the object. This parameter is mandatory. String

 

The qId property is used when it comes to apply a created Bookmark or when we want to destroy (remove) the created Bookmark from our app. Here the code snippet which shows how to create a Bookmark through Enigma. Do not forget to save the changes after the creation of the bookmark when you are using the Qliksense Destkop.

enigmaModel.createBookmark(bookmark).then((model) => {

    model.getLayout().then(layout => {

        if (storedBm == undefined || storedBm == null) {
            storedBm = [];
        }

        if (storedBm.length == 0) {
            $("#bmTable").find("tr:gt(0)").remove();
        }

        storedBm.push(bookmark);
        localStorage.setItem("bookmarks", JSON.stringify(storedBm));

        var row = '<tr>';
        row += '<td align="center">' + layout.qInfo.qId + '</td>';
        row += '<td align="center">' + layout.qInfo.qType + '</td>';
        row += '<td align="center">' + layout.creationDate + '</td>';
        row += '<td align="center"><button class="ng-isolate-scope lui-button">Apply</button></td>';
        row += '</tr>';

        $('#bmTable tr:last').after(row);

        //PAM: Save in case we are using Qliksense Desktop
        global.isPersonalMode(function(reply) {
            isPersonalMode = reply.qReturn;
            if (isPersonalMode) {
                console.log('Personal Mode!');
                enigmaModel.doSave();
            }
        });
    });
});

Conclusion
As you have seen the creation of bookmarks are pretty straight forward and it allows us to save the state of our app at a specific time point in an easy manner thanks to the enigma library. You can ceck out the extension on my GITHUB profile! There is actually a feature in Qlik Sense that uses bookmark for this purpose: the snapshot feature is built on bookmarks.