BigBear.ai
  • Home
  • Industries
    • Academia
    • Government
    • Healthcare
    • Manufacturing
  • Solutions
    • Cyber
    • Data Analytics
    • Enterprise Planning and Logistics
    • Intelligent Automation
    • Modeling Solutions
    • Professional Services
  • Company
    • About
    • Investor Relations
    • Partners
    • Team
  • Careers
    • Benefits
    • Culture
    • Explore Jobs
    • Military and Veterans
    • Applicant Login
    • Employee Login
  • Resources
    • Blog
    • Events
    • Newsroom
    • Resource Library
    • Online Store
  • Contact
Search

Home Qlik Qlik Extension Development and API Calls

Blog

Qlik Extension Development and API Calls

Paul Pirolli
January 19, 2021
  • Share
  • Share

Qlik Extension Development

I recently had a requirement to add a button to download an NPrinting report without navigating from the sheet of an app. At first glance, I thought I would use the NPrinting On-Demand report generator that Qlik supports, but I found a few issues using it. The required button was to generate a report on another app, and while the app with the button had some filters with ‘only one selected value’ on a field, the report was supposed to loop through the values in the restricted field & produce a PowerPoint presentation. Here are some of the issues

  • The NPrinting On-Demand report generator can generate a report from the current app or another app. However, when generating from another app, it worked similar to ODAG report generation in that it passed selections to the 2nd app. This filtered our results in the report.
  • The NPrinting report took some time to generate. Our solution could run a job every morning & create the report before the user requested it.
  • Each user has a different “shared folder” for the download, meaning that the GUID for the folder changed for each user. This made it impossible to hard-code the solution (and who wants to hard-code a solution anyway…)

Lucky for me, I had finished updating an extension that populates a sidebar with the stream, app, & page for navigation so that the user never accesses the Qlik hub, and the API calls for the NPrinting report are executed the same way. Development of this button only took a couple of hours. Here is how.

How to develop extensions in Qlik

Qlik client-side extensions use Javascript, HTML and CSS. Javascript is where the magic happens, so let’s start there.

Starting off: use a template

First, this extension will be built in the Qlik Dev Hub. As far as I know, the desktop version does not support the API calls we will be making.

Navigate to the Dev Hub by logging onto your Qlik enterprise instance and clicking the ellipsis on the top right of the page.

 

From here, navigate to Extension Editor, create an extension, provide a name & select “Angular Basic Visualization template.” Although I do not use angular in this extension, this template provides the bones I work with in my extension.

 

 

Template layout

There should be 3 tabs open in your development area now, a .qext, .js, and .html tab. We will ignore the .qext tab during this blog, and change up the angular references in the .js and .html. I will not go into deep detail on how all of this works as I want to focus on my solution, so let’s get to work. We’ll start on the .js tab which should look like this:

define( ["qlik", "text!./template.html"],
  function ( qlik, template ) {
    return {
    template: template,
    support: {
      snapshot: true,
      export: true,
      exportData: false
    },
    paint: function () {
      return qlik.Promise.resolve();
    },
    controller: ['$scope', function ( $scope ) {
      //add your rendering code here
      $scope.html = "Hello World";
    }]
  };
} );

We will be adding all our code in the controller, so let’s get started.

Ajax calls

Ajax calls are the way we will perform a request to the Qlik engine to retrieve results. Check out the documentation of Ajax calls on W3schools.com here. This is the syntax we’ll use:

$.ajax({
    url: "endpoint here",
    type: "GET",
    headers: {
      "add here"
    },
    success: function (object){
      //do something
    },
    error: function (error){
      console.log(error);
    }
});

The URL is where I would add my endpoint for my Qlik request, and then handle the request-response after “success”. Logging the response is a good way to start & inspect the object; log as follows by pasting the line below under the ‘//do something’ line.

console.log(object);

This will log out the response on the developer web console on the webpage (Qlik Sense page) that the extension is dropped into.

Endpoints for Qlik: QRS & QPS

From here, I looked up the endpoint for shared content libraries on Qlik Sense in the QRS API documentation. The endpoint I need to hit is “/qrs/sharedcontent/full”. The documentation also indicates what parameters are necessary, so in the end my ajax request looked like this:

$.ajax({
   url:"/qrs/sharedcontent/full?xrfkey=GAMG717cpRsrx7xR",
   type: "GET",
   headers: {
     "X-Qlik-XrfKey":"GAMG717cpRsrx7xR"
   },
   success: function (sharedContent){
     console.log(sharedContent);
   },
   error: function (error){
     console.log(error);
   }
});

Dropping the extension on a sheet in Qlik Sense, I can inspect my sharedContent library by opening developer tools on the webpage. There should be an array logged out that looks something like this when expanded.

 

Each of the objects in this array is a sharedContent library that belongs to a user. I only need the current user, so I have to add a filter. Filters can be passed in the Ajax call, and I can use a qps endpoint to retrieve the current user (n.b. there is an endpoint in the QRS for users, but this will retrieve all users. Since we want to get the current user, the Qlik Proxy Service endpoint (qps) is the best to use). Now I have a 2nd Ajax request:

"/qps/user"

Asynchronous Javascript

I now call this endpoint first & use the response to filter the sharedContent call. It is important to note here that Javascript is an asynchronous language, meaning that it does not execute line 1, then line 2. It can execute several commands at the same time, and dependencies must be embedded within the call to ensure data is available. This is what our filtered sharedContent library call will now look like, embedded within our User call:

$.ajax({
  url:"/qps/user?xrfkey=GAMG717cpRsrx7xR",
  type: "GET",
  headers: {
    "X-Qlik-XrfKey":"GAMG717cpRsrx7xR"
    },
  success: function (user){
    $.ajax({
      url:"/qrs/sharedcontent/full?xrfkey=GAMG717cpRsrx7xR&filter=owner.name eq '" + user.userName + "'",
      type: "GET",
      headers: {
        "X-Qlik-XrfKey":"GAMG717cpRsrx7xR"
      },
      success: function (sharedContent){
        console.log(sharedContent);
      },
      error: function (error){
       console.log(error);
      }
    });
   },
   error: function (error){
     console.log(error);
   }
});

Save the script & refresh the Qlik Sense page. Now there should only be one shared library belonging to the current user (or none if the current user does not have a shared library).

Filtering response

The filtering API call documentation provided by Qlik is a great area to become acquainted with if looking to add filters to calls.

Final items: handling object

Now that I had all the information in my call that I needed (notice that I did not filter based on report name – I only have one report from NPrinting at this time, so I did not need to do that. An instance with more than one report would have required another filter), I just needed to retrieve the proper URL. I found that there were versions offered by NPrinting within the object, so I had several URLs. I decided I wanted only the most recent, and since the url was structured as /sharedcontent/[GUID]/[TimeStamp of report]/[ReportName], I created an array and sorted it descending. Then I used the first sorted value as my URL.

success: function (sharedContent){
   console.log(sharedContent);
   var nPrintingEndpoint = []; //empty array
   for(i=0;i < sharedContent[0].references.length;i++){
       nPrintingEndpoint.push(sharedContent[0].references[i].externalPath);
   }
   //console.log(nPrintingEndpoint);
   nPrintingEndpoint.reverse();
   window.open(nPrintingEndpoint[0], '_blank');
}

Target acquired. Now I just need to tie this to the front end.

HTML Binding

Time to bind it. Let’s start with our .html file. It should look like this:

<div qv-extension style="height: 100%; position: relative; overflow: auto;" class="ng-scope">
{{ html }} 
</div>

I worked on this a little and found after a little research that I could change it to a button & bind it without using the angular {{ html }}. This is what it looked like when I finished:

<div qv-extension style="height: 100%; position: relative; overflow: auto;" class="ng-scope">
    <button class="myQlik-button" id="NPrintButton">Generate My Report</button>
</div>

Now I need to bind it to my javascript. So I made the following changes:

  • In the controller, I wrapped my first $.ajax call in a function
  • I used my HTML object id with a .onclick to bind the function to my html button

Now the code looks like this:

controller: ['$scope', function ( $scope ) {
    //add your rendering code here
    NPrintButton.onclick = function retrieveReport(){
      $.ajax({
        ...
      });
    }
}]

CSS

Time to brush things up with some CSS. Add a new tab using the “+” symbol on the top right of the screen of the edit extension window. I called the new item styles.css. I added a few things here to make it blend with the custom theme my client was using, and ensure that the object changed when hovered over with the mouse.

styles.css
/* CSS */
.myQlik-button {
    height:100%;
    width:100%;
    background-color: #404040;
    color: #ffffff;
    font-family: "QlikView Sans";
}

.myQlik-button:hover {
    cursor: pointer;
    background-color: gray;
};

Finish this by adding a reference to the styles in the .js document as outlined below:

define( ["qlik", "text!./template.html","css!./styles.css"],

Conclusion

Overall, this experience helped me gain confidence using the Qlik QRS & QPS endpoints. I hope this walk-through might inspire you to jump into the deep end of Qlik Extension development.

Happy Qliking.

Posted in Qlik.
BigBear.ai
  • Home
  • Industries
  • Solutions
  • Company
  • Careers
  • Blog
  • Investor Relations
  • Contact
  • Twitter
  • Facebook
  • Linkedin
  • Google My business for BigBear.ai
1-410-312-0885
[email protected]
  • Privacy Policy
  • Terms of Use
  • Accessibility
  • Site Map
© BigBear.ai 2023
We value your privacy
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept”, you consent to the use of ALL the cookies.
Privacy Policy | Do not sell my personal information
AcceptCookie Settings
Manage Consent

Cookies Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary
Always Enabled
Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.
CookieDurationDescription
cookielawinfo-checkbox-analytics11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional11 monthsThe cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
JSESSIONIDsessionThe JSESSIONID cookie is used by New Relic to store a session identifier so that New Relic can monitor session counts for an application.
viewed_cookie_policy11 monthsThe cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
CookieDurationDescription
__atuvc1 year 1 monthAddThis sets this cookie to ensure that the updated count is seen when one shares a page and returns to it, before the share count cache is updated.
__atuvs30 minutesAddThis sets this cookie to ensure that the updated count is seen when one shares a page and returns to it, before the share count cache is updated.
Analytics
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
CookieDurationDescription
_ga2 yearsThe _ga cookie, installed by Google Analytics, calculates visitor, session and campaign data and also keeps track of site usage for the site's analytics report. The cookie stores information anonymously and assigns a randomly generated number to recognize unique visitors.
_ga_NK4L4Q320Q2 yearsThis cookie is installed by Google Analytics.
_gat_gtag_UA_163894009_21 minuteSet by Google to distinguish users.
_gid1 dayInstalled by Google Analytics, _gid cookie stores information on how visitors use a website, while also creating an analytics report of the website's performance. Some of the data that are collected include the number of visitors, their source, and the pages they visit anonymously.
at-randneverAddThis sets this cookie to track page visits, sources of traffic and share counts.
CONSENT2 yearsYouTube sets this cookie via embedded youtube-videos and registers anonymous statistical data.
uvc1 year 1 monthSet by addthis.com to determine the usage of addthis.com service.
Advertisement
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.
CookieDurationDescription
f5avraaaaaaaaaaaaaaaa_session_sessionbusinesswire.com cookie
loc1 year 1 monthAddThis sets this geolocation cookie to help understand the location of users who share the information.
VISITOR_INFO1_LIVE5 months 27 daysA cookie set by YouTube to measure bandwidth that determines whether the user gets the new or old player interface.
YSCsessionYSC cookie is set by Youtube and is used to track the views of embedded videos on Youtube pages.
yt-remote-connected-devicesneverYouTube sets this cookie to store the video preferences of the user using embedded YouTube video.
yt-remote-device-idneverYouTube sets this cookie to store the video preferences of the user using embedded YouTube video.
Save & Accept