Using CoffeeScript to create QlikView extensions

I am not a Javascript fan. To be honest, I find it rather abusive. There are probably lots of theoretically sound reasons for designing the Javascript (=JS) syntax the way it is – but that does not make it more readable or easy to learn.

I am however a QlikView (=QV) fan. Or rather: QV is a very powerful data visualisation, exploration and discovery tool, but the main drawbacks is its somewhat dated visualisation options. In a world used to fancy angular.js based dynamic web sites and great looking HighCharts graphs, QV’s visualisation options aren’t quite up there.

QV however has a rather interesting “extension” mechanism. You can create object extensions that add new visualisations to QV, using JS to develop the extensions. Document extensions are used to modify the deeper levels of QV applications – very useful and cool (someone created a document extensions using the accelerometers in iPhones to enable new ways to interacts with QV applications – pretty cool!) but not the focus of this post.

So, we want to create QlikView object extensions. JS is the mandated language. Ouch. We can however use CoffeeScript to remove the bad parts of JS, making the code base smaller and more easy to read and maintain. CoffeeScript is very cool, lots of testimonies to it’s greatness out there (DropBox is using CoffeeScript these days, and have shared some experiences).

Note: You need to install node.js before CoffeeScript. I’ve tried this on both Windows 8.1 and OS X – compiling CoffeeScript works without problems on both platforms.

Tuns out this works quite well. Brian Munz of QlikTech has created a couple of very nice templates to make it easier to create extensions, I’ve taken the liberty of converting one of them to CoffeeScript, to show how easy it is to convert JS to CoffeeScript (and make my own future extension development easier).

The CoffeeScript code can also be found in my repo at GitHub.

The Javascript version first:


var template_path = Qva.Remote + "?public=only&name=Extensions/template_simple/";
function extension_Init()
{
  // Use QlikView's method of loading other files needed by an extension. These files should be added to your extension .zip file (.qar)
  if (typeof jQuery == 'undefined') {
    Qva.LoadScript(template_path + 'jquery.js', extension_Done);
  }
  else {
    extension_Done();
  }
}

function extension_Done(){
  //Add extension
  Qva.AddExtension('template_simple', function(){
    //Load a CSS style sheet
    Qva.LoadCSS(template_path + "style.css");
    var _this = this;
    //add a unique name to the extension in order to prevent conflicts with other extensions.
    //basically, take the object ID and add it to a DIV
    var divName = _this.Layout.ObjectId.replace("\\", "_");
    if(_this.Element.children.length == 0) {//if this div doesn't already exist, create a unique div with the divName
      var ui = document.createElement("div");
      ui.setAttribute("id", divName);
      _this.Element.appendChild(ui);
    } else {
      //if it does exist, empty the div so we can fill it again
      $("#" + divName).empty();
    }

    //create a variable to put the html into
    var html = "";
    //set a variable to the dataset to make things easier
    var td = _this.Data;
    //loop through the data set and add the values to the html variable
    for(var rowIx = 0; rowIx < td.Rows.length; rowIx++) {
      //set the current row to a variable
      var row = td.Rows[rowIx];
      //get the value of the first item in the dataset row
      var val1 = row[0].text;
      //get the value of the second item in the dataset row
      var m = row[1].text;
      //add those values to the html variable
      html += "value 1: " + val1 + " expression value: " + m + "<br />";
    }
    //insert the html from the html variable into the extension.
    $("#" + divName).html(html);
  });
}

//Initiate extension
extension_Init();

Now the CoffeeScript version. A lot more readable, at least to me:

template_path = Qva.Remote + "?public=only&name=Extensions/template_simple_coffeescript/"

extension_Init = ->
  # Use QlikView's method of loading other files needed by an extension. These files should be added to your extension .zip file (.qar)
  if typeof jQuery == 'undefined'
    Qva.LoadScript(template_path + 'jquery.js', extension_Done)
  else
    extension_Done()

extension_Done = ->
  # Add extension
  Qva.AddExtension('template_simple_coffeescript', ->
    _this = this

    # add a unique name to the extension in order to prevent conflicts with other extensions.
    # basically, take the object ID and add it to a DIV
    divName = _this.Layout.ObjectId.replace("\\", "_")
    if _this.Element.children.length == 0
      # if this div doesn't already exist, create a unique div with the divName
      ui = document.createElement("div")
      ui.setAttribute("id", divName)
      _this.Element.appendChild(ui)
    else
      # if it does exist, empty the div so we can fill it again
      $("#" + divName).empty()

    # create a variable to put the html into
    html = ""

    # set a variable to the dataset to make things easier
    td = _this.Data

    # loop through the data set and add the values to the html variable
    for rowIx in [0..(td.Rows.length-1)]

    # set the current row to a variable
    row = td.Rows[rowIx]

    # get the value of the first item in the dataset row
    val1 = row[0].text

    # get the value of the second item in the dataset row
    m = row[1].text

    # add those values to the html variable
    html += "value 1: " + val1 + " expression value: " + m + "<br />"

    # insert the html from the html variable into the extension.
    $("#" + divName).html(html)
  )

# Initiate extension
@extension_Init()

Note that you need to include the –bare option when compiling the CoffeeScript code:


coffee --bare --compile Script.coffee

This will give us the following Javascript file, which is functionally equivalent to the first JS file above:

// Generated by CoffeeScript 1.6.3
var extension_Done, extension_Init, template_path;

template_path = Qva.Remote + "?public=only&name=Extensions/template_simple_coffeescript/";

extension_Init = function() {
  if (typeof jQuery === 'undefined') {
    return Qva.LoadScript(template_path + 'jquery.js', extension_Done);
  } else {
    return extension_Done();
  }
};

extension_Done = function() {
  return Qva.AddExtension('template_simple_coffeescript', function() {
    var divName, html, m, row, rowIx, td, ui, val1, _i, _ref, _this;
    _this = this;
    divName = _this.Layout.ObjectId.replace("\\", "_");
    if (_this.Element.children.length === 0) {
      ui = document.createElement("div");
      ui.setAttribute("id", divName);
      _this.Element.appendChild(ui);
    } else {
      $("#" + divName).empty();
    }

    html = "";
    td = _this.Data;
    for (rowIx = _i = 0, _ref = td.Rows.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; rowIx = 0 <= _ref ? ++_i : --_i) {
      row = td.Rows[rowIx];
      val1 = row[0].text;
      m = row[1].text;
      html += "value 1: " + val1 + " expression value: " + m + "<br />";
    }
    return $("#" + divName).html(html);
  });
};

this.extension_Init();
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s