September 1, 2011

Building extensions in QlikView: some hints & tips

Here are some useful hints & tips that I learned while working over Explainum Feeds -- our extension for creating context-dependent comments in QlikView applications.

First of all, I would like to thank Stephen Redmond for his very useful Beginners Guide to QlikView Extension Objects (part 1, part 2, part 3, part 4) -- a mustread for everyone who starts developing extensions.

If you have done with that guide then these hints might be useful for you as well:
  • Namings
  • Debugging the extension
  • Getting custom properties
  • Accessing other objects
  • Using external CSS stylesheets
Namings
Make sure that names of extension folders in Windows and corresponding names in extension files like definition.xml, script.js are in the same case. QlikView is sensitive to this.

Debugging the extension
Task #1 and may be the simplest one. Load FireBug Lite before loading script.js:

var
extCallback = function () {
  //let's explore extension object in details
  console.log(this);
}

Qva.LoadScript('https://getfirebug.com/firebug-lite-beta.js#startOpened=true', function () {
    Qva.LoadScript(qva.Remote + '?public=only&name=Extensions/MyExtension/script.js', function () {
      Qva.AddExtension('
MyExtension', extCallback);
   });
});



Getting custom properties
This is one of the earliest tasks when developing custom extension -- how to get custom parameters from the extension properties.

As you know from Stephen's guide there are 2 major components of an extension: definition.xml and script.js. Besides these two there is 3rd important file that we will need as well: properties.qvpp which is located in the extension folder also.

First, add necessary lines to definition.xml. If you need say 2 custom parameters then add 2 lines for each parameter as in the sample below:

<?xml version="1.0" encoding="utf-8"?>
<ExtensionObject Label="MyExtension" Description="My Extension">
    <Dimension Initial="" />
    <Measurement Initial="" />
    <Text Initial="" Expression="" />
    <Text Initial="" Expression="" />
</ExtensionObject>


Lines related to custom fields are highlighted

Properties.qvpp is HTML-like template for the properties window of extension (it's not pure HTML as it seems like it is parsed before transforming into HTML of properties window). Its structure is pretty straight forward for those who are more or less familiar with HTML. It has several standard sections (like Layout, Caption, Access) and may include custom sections as well. Below is sample properties.qvpp with definition of two custom parameters:

<div class="ToolWindow-MainBody">
  <table width="360px">
    <tr class="ToolProperty-Header" >
      <td onclick="Qva.SelectToolPane(this, false)">
        MyExtension
      </td>
      <th onclick="Qva.SelectToolPane(this, true)">
        <img alt="" src="unpinned.png" icon="web:unpinned" avq="img:.Chart.Title"/>
      </th>
    </tr>
    <tr>
      <td colspan="2">
        <table width="100%">
          <colgroup>
            <col width="130px" />
            <col width="190px" />
            <col width="30px" />
          </colgroup>
          <tr>
            <td class="ToolProperty-Literal">
              Parameter A:
            </td>
            <td colspan="2">
              <input style="width: 200px" avq="edit:.Chart.Text.0.Content" />
            </td>
          </tr>
          <tr>
            <td class="ToolProperty-Literal">
              Parameter B:
            </td>
            <td colspan="2">
              <input style="width: 200px" avq="edit:.Chart.Text.1.Content" />
            </td>
          </tr>
        </table>
      </td>
    </tr>
    <tr class="ToolProperty-Header" avq="panel::Layout.qvpp"><td>Layout</td><th></th></tr>
    <tr style="display: none"><td colspan="2"></td></tr>
    <tr class="ToolProperty-Header" avq="panel::Caption.qvpp"><td>Caption</td><th></th></tr>
    <tr style="display: none"><td colspan="2"></td></tr>
    <tr class="ToolProperty-Header" avq="panel::Access.qvpp"><td>Access</td><th></th></tr>
    <tr style="display: none"><td colspan="2"></td></tr>
  </table>
</div>


Notice highlighted IDs for custom fields.

Finally, let's get values of custom parameters in script -- add two lines into function extCallback defined in the example above:

var extCallback = function () {
  //this <- points to extension object
  var paramA = this.Layout.Text0.text;
  var paramB = this.Layout.Text1.text;
}


Accessing other objects
This is one of the trickiest things in extensions which may cause some confusion. When dealing with other objects (like listboxes, textboxes, charts and other extensions) it is important to understand that all objects in QlikView WebMode are created in asynchronous mode. This means that one object can exist in point of time when other objects still are not created. Therefore, to access other objects you should use callback functions. Callback functions can be assigned to objects using qva.GetQvObject function. Here is an example of modified extCallback function:

var listboxCallback = function () {
    var caption = this.Layout.Caption.label;
    alert(caption);
}
var extCallback = function () {
    qva.GetQvOvbject("LB01", listboxCallback);
}


There is one more way to access object properties using QvaPublic method. But you have to be sure that accessed object is constructed and valid which is not always true as qva.GetQvObject always returns at least blank object with some basic properties.

var lb_obj;

var listboxCallback = function () {
   var caption = lb_obj.QvaPublic.Layout.Caption.label;
   alert(caption);
}

var extCallback = function () {
   lb_obj = qva.GetQvOvbject("LB01", listboxCallback);
}


Here LB01 is object ID which can be seen in General tab of object properties window in QlikView. Remember to assign callback function to an object only once as every call of qva.GetQvObject doesn't replace callback function but adds a new one.

Using qva.GetQvObject you can also access objects from other sheets of a QV application as well, but keep in mind that they have to be constructed and valid prior to accessing them.

Using CSS stylesheets
One day you would want your extension look nicer. It is not so convenient to define complex styles right in HTML, as they can be very lengthy. Much better way is to use external CSS stylesheets, which can be inserted into browser DOM from within extension. Create styles.css in the extension folder and then use it as in the following example:

var cssref = document.createElement("link");
cssref.setAttribute("rel", "stylesheet");
cssref.setAttribute("type", "text/css");
cssref.setAttribute("href", qva.Remote + "?public=only&name=Extensions/MyExtension/styles.css");
document.getElementsByTagName("head")[0].appendChild(cssref);