☰  Topseed™ Tutorial
  ☰ Topseed™ Tutorials

Lab 5: UI Reading from an API

  1. Download and unzip topseed-master.zip from https://github.com/topseed/topseed to your location of choice on your developer machine. For this and the next lab, we use the 'dynamic', server-side features of Node.js. If you have not installed Node.js on your machine, follow the instructions in lab 3.3. to install it. Then select menu View-Integrated Terminal. On the command line that opens, change directory with 'cd demo-topseed-io'. Type 'npm install' and hit Enter. Once the dependencies installation completes, type 'node index [Enter]'.

  2. We will now work on an 'Admin' module that allows listing (and adding to) a 'Linkblog', or list of links. In a browser, go to http://localhost:8091 and click on the 'Admin' menu item to navigate to the 'Topseed Admin Console' (We will add login security in tutorial 7). The Admin module has its own appshell and menu (see /_part/admin/). To signal a full screen refresh to turbo, we added a '#' to the link that leads to the Admin home screen at http://localhost:8091/admin/home/#. The refresh ensures that the standard menu (which would otherwise remain 'cached' and re-displayed) is replaced by the Admin menu.

  3. Click on the 'Linkblog' menu item at http://localhost:8091/admin/linkblog/to navigate to a list of linkblog items. Rather than composing a screen in full on a server, modern web apps often take a HTML page to the browser first and then let the browser call an API to 'fill in' the data, using JavaScript. This way, the static elements of a page can be served by a fast CDN, and the dynamic/data parts can be obtained directly from the data source.

  4. The linkblog list is populated with data coming from a JSON response to an API call. By default, the tutorial project is configured to obtain the API response from a file at /public/linkblog/dummy.json or http://localhost:8091/linkblog/dummy.json. However, in the next tutorial we will call a real, live database API that resides on a separate API server.

  5. Now click the 'Add Item' button and note how the browser URL changed to http://localhost:8091/admin/linkblog/detail.html. This is a stable URL for the the data entry form to add/write a new item. 'Stable URL' means that page is not lost when you hit the browser refresh button, and that the page is 'bookmarkable', which is almost always a good thing. For now, click 'Cancel' to return to the list at http://localhost:8091/admin/linkblog/.

  6. Inspect /public/admin/linkblog/index.pug. This file defines the composition of the linkblog list screen. In the 'HTML' part of this file, the list is represented by the pug statement 'table#grid' ('<table id="grid">'). The 'script.' part of the file is responsible for causing the grid data to be loaded and rendered. The dot at the end of 'script.' tells Pug to not convert what follows to HTML.

  7. In 'script.' we load external JavaScript that encapsulates logic, which keeps the page HTML clean and designer-friendly. In this example 'TS.loadOnAppReady' loads /admin/linkblog/LinkblogBusiness.js, then calls the 'UIinit' function in the page. This function triggers the 'list' function of LinkblogBusiness, which asynchronously loads data from the API, and — once the data has been received — renders the grid as well as the data in the grid. Depending on how much data is to be loaded, a more advanced version of LinkblogBusiness could have a separate function (e.g. 'init()') to first render the grid without data, and the 'list()' function would only load and render the list items.

  8. Open /public/admin/linkblog/LinkblogBusiness.js and scroll to the end of the file. See how LinkblogBusiness wraps a 'SimpleBusiness' object instance named 'sb' that is returned to the page after we added a LinkblogDao Data Access Object (DAO) instance. The page-specific custom functionality of SimpleBusiness is added close to the top of the file, beginning with 'var SimpleBusiness = BLX.extend({'. We keep common business functionality in a base 'class' named BLX.js ('BusinessLogiX'), and common data service functionality in BDS.js (BaseDataService). Both are loaded by /_js/admin.js, the 'admin module version' of main.js.

  9. In LinkblogBusiness.js we use 'var SimpleBusiness = BLX.extend({' instead of the more recent 'class SimpleBusiness extends BLX {', because Internet Explorer (IE) does not support 'class'. However, Microsoft's 'Edge' browser supports it. We will use 'class' once IE has lost its remaining popularity; see /admin/linkblog/LinkblogBusiness2.js for an example. Note the resulting improvement in function signatures e.g. 'list()' vs ',list: function()'. If you can exclude the use of IE (such as for an internal web-app or a mobile app) we recommend you use the 'class' version. You can read more about the IE-compatible version at http://johnresig.com/blog/simple-javascript-inheritance. To use the 'class' version, in this example you would use TS.loadOnAppReady('/admin/linkblog/LinkblogBusiness2.js' in /admin/linkblog/index.pug and /detail.pug and change /_js/admin.js to load BLX2.js and BDS2.js instead of BLX.js and BDS.js.

  10. In LinkblogBusiness.js, inspect the code section following ', list: function(listId)'. The JavaScript in /admin/linkblog/index.pug triggers this function with 'sb.list('#grid')'. Brushing over the details of obtaining the data for now, this function receives a '_listPromise' of data from the configured API. When data is returned, the function '_renderList' enters '_listPromise.then(function(values){', builds the grid with the received values (a JSON array of rows) and renders it in the page element with id 'grid'. There are many ways to render lists. In this example we use https://dataTables.net/ to deliver advanced grid sorting, searching and paging features.

  11. JavaScript promises are a modern way to manage process flow. They are especially useful for handling asynchronous calls such as HTTP requests to an API that may require error handling, such as connection errors. They replace classic asynchronous callbacks that are prone to 'Callback Hell'; see http://callbackhell.com. A lot of public APIs, such as Google Firebase, use or allow the use of promises, and you can 'promisify' those that don't. Promises are important, learn how they work at http://www.telerik.com/blogs/what-is-the-point-of-promises. The post https://stackoverflow.com/questions/22539815/arent-promises-just-callbacks may also help.

  12. The LinkblogDao Data Access Object is responsible for obtaining the raw list data. See 'urlSpec' at the top of LinkblogBusiness.js and how LinkblogDao extends BDS (which contains common data access functionality). Also see at the bottom of LinkblogBusiness.js how urlSpec is passed to LinkblogDao with 'sb.linkblogDao = new LinkblogDao(urlSpec)'. Unlike SimpleBusiness, in this case LinkblogDao has no added functionality, so we could write 'sb.linkblogDao = new BDS(urlSpec)' instead.

  13. Inspect '/_js/BDS.js and its 'selectList' function. It calls a shared static '_get' function which uses 'fetch_' to call the urlSpec URL and returns a promise of the response content. Fetch is a modern replacement for Ajax/XMLHttpRequest. Fetch uses promises! Read more about Fetch at https://davidwalsh.name/fetch. At the end of the next lab we learn how an API server can handle this fetch request. In this lab, the content of /public/linkblog/dummy.json or http://localhost:8091/linkblog/dummy.json is returned.