Single Page Applications and kdb+: AngularJS

5 November 2020 | 6 minutes

By Stephen Trainor

This blog post is the third of a series, which demonstrates how different front-end technologies can be used with kdb+. The technology discussed in this post is called AngularJS which is a legacy JavaScript (JS) framework created by Google, offering a range of benefits, including built-in directives, two-way data-binding and pre-built components. AngularJS has been succeeded by Angular, which was covered in the previous post. AngularJS is currently scheduled to leave Long Term Support in December 2021, but is still widely used throughout the industry; it is hoped that this blog series may be of use to any developers who are evaluating other technologies to replace it with.

The SPA application discussed in this blog contains two tabs. The first is a calendar, which demonstrates cell editing and pagination. The second doesn’t contain any functionality and is just present to demonstrate URL routing for this technology.

Common SPA Features

Websockets and Promises are used throughout all of the technologies in this series, and are discussed in the first entry, which focuses on React and is posted on this link. It also provides a brief introduction to what a Single-Page Application is.

AngularJS

This AngularJS implementation uses a python webserver, which is chosen because it requires minimal setup. The python server doesn’t track file-caching, so any updates to js or CSS files may not overwrite the cached version. This can be solved with a hard refresh (ctrl+shift+r), or by incrementing the version every time the file is changed:

  • Download source code from Github.
  • Install Python.
  • Depending on your downloaded Python version, edit startP2.bat or startP3.bat to use the correct Python file-path, and run the corresponding file.
  • Run startQ.bat – if you aren’t using C:\q\w64, this file will need to be edited.
  • View from a browser:
  • http://localhost:5000/angularJSProject/html/index.html 

Optional Libraries

jQuery is useful for DOM manipulation and UI templates 

Lite-server is a development library which refreshes the loaded HTML, JS and CSS files when they are changed, avoiding the need to perform hard refreshes or incrementing the version like so:

<script src="../js/main.js?version1"></script>

Structure

  • index.html
    • tab0.js
    • tab1.js
    • index.js
      • tab0.html
      • Tab1.html

index.html loads all of the required js files at startup.
index.js has a routeProvider which instructs index.html to load the relevant html file depending on the url.

Scopes and ng-controller

AngularJS projects have a HTML attribute called ng-controller, as shown in tab0.html:

<div ng-controller="ctrl0" style="display:flex; min-height:550px">
  <table ng-hide="cal.shownSnack"
    …
  </table>
</div>

ng-controller tells the nested HTML that it should look in the JS code of the controller for any referenced variables. In this case, ng-hide uses a variable called cal.shownSnack, which is defined in the controller called “ctrl0” in tab0.js:

app.controller('ctrl0', ctrl0);
ctrl0.$inject = ['$scope', '$rootScope', 'rs'];
function ctrl0($scope, $rootScope, rs) {
  …
  cal.postGetCalendar = function(data){
    cal.shownSnack=false;
    …
  };
};

The above code also features the injection of scopes and ‘rs’. Similar to namespaces in q, scopes are dictionaries which can contain functions, variables or further dictionaries. However, each controller only has access to its own scope, and cannot access the scope of other controllers. Variables and functions which should be accessible to multiple controllers can be stored in the rootScope.

‘rs’ is a service defined in index.js, which has been made available to the controllers of both tabs, so that websocket does not need to be reloaded when navigating between tabs.

app.service('rs', function($rootScope){…}

Directives

AngularJS comes with many predefined directives, which allow the developer to simply generate the desired HTML. Some directives used in this project are explained below. The full list can be found here.

  • ng-model: This creates a two-way data binding between a variable and a form. If the variable is updated by JS, the form should change accordingly, and vice-versa. Sometimes these changes aren’t detected, and can be forced using $digest or $apply.
  • ng-change: This triggers the provided expression when a user makes a change to a form.
  • ng-repeat: This duplicates a HTML element multiple times, with content and length related to the provided variable.
  • ng-class: This uses the provided expression to determine what class should be applied to an element.
  • ng-blur: This triggers the provided expression when the element loses focus.
  • ng-hide/ng-show: This uses the provided expression to determine whether the element should be hidden or shown.

ng-view: This is used in combination with routeProvider to render different HTML files depending on the url

Sample Project


Animated Calendar Built in kdb - KX

AngularJS SPA – Consists of a calendar with editable cells, and a separate tab to demonstrate routing

Rendering a table

Kdb+

In the calendar tab, a table with 8 rows is displayed on the front end, and refreshes as the user scrolls:

.cal.getCalendar:{[index]
  t:update hiddenIndex:i from cal;
  select ["j"$index,8] from t
};
.cal.getCalendar:{[index]
  t:update hiddenIndex:i from cal;
  select ["j"$index,8] from t
};

AngularJS

<table ng-hide="cal.shownSnack" style="display:inline-table; vertical-align:top" class="table border="1">
    <th ng-repeat="col in cal.calendarKeys"ng-class="cal.headerWidth(x)">{{cal.formatHeader(col)}}</th>
    <tr ng-repeat="cal in cal.calendar">
      <td ng-repeat="col in cal.calendarKeys"
          ng-class="cal.highlightDate(cal[col])"
          contenteditable="{{col.includes('Comment')}}"
          ng-blur="cal.editRow((cal.index+$parent.$index), col, $event)"
          >{{cal.formatCell(cal,col)}}
      </td>
    </tr>
  </table>

Editing a Table

This contains three ngFors – one for the column names, one for the column rows, and one for the column cells.

kdb+

When the user edits a cell in the calendar tab, .cal.editRow is called. It formats the text provided by the user, and overwrites that table cell in memory using a functional select.

.cal.editRow:{[index; kolName; kolVal]
  index:"j"$index;
  kolName:`$kolName;
  t:`cal;
  kolType:type (value t)[kolName];
  //Only include numbers in number fields
  if[kolType in "h"$5+til 5; kolVal@:where kolVal in .Q.n,"-."];
  //Cast to the appropriate datatype
  kolVal:(neg kolType)$kolVal;
  if[kolType=0h; kolVal:(enlist; kolVal)];
  if[kolType=11h; kolVal:enlist kolVal];
  //update kolName:kolVal from cal where i=index
  ![t; enlist(=;`i;index); 0b; (enlist kolName)!enlist kolVal];
}

AngularJS

Blur is used to trigger a function when the cell gains or loses focus.

cal.editRow = function(i, kol, data){
      data=data.srcElement.innerText;
      return ws.qPromise(".cal.editRow",[i, kol, data]);
};

In conclusion, AngularJS is a legacy SPA framework which is simple to set up and can provide a fast and responsive browsing experience. This blog discussed its benefits, such as built-in directives, two-way data-binding and standardised components, and should serve as a suitable introduction to getting started with AngularJS and coupling it with kdb+. 

The front and back-end code outlined above are available in GitHub on this link

 

Demo kdb, the fastest time-series data analytics engine in the cloud








    For information on how we collect and use your data, please see our privacy notice. By clicking “Download Now” you understand and accept the terms of the License Agreement and the Acceptable Use Policy.