Skip to Content

This project demonstrates how to develop an offline enabled OpenUI5 stock application using the AppCache API and LocalStorage. The app is stored inside the browser and does not need a native shell to be offline enabled.

You can try it out here:

https://pensoffsky.github.io/OpenUI5-AppCache/index.html

Sources:

GitHub – pensoffsky/OpenUI5-AppCache

Features

The app is able to run offline in all current browsers. It implements a very basic stock application. The last fetched data is persisted in the browser and even in airplane mode the app is reachable and will display the last fetched stock quotes.

Concepts

AppCache for UI5 & app resources

The manifest.appcache file defines which resources shall be stored in the browser for offline usage.


    CACHE MANIFEST
    resources/sap-ui-core.js
    resources/sap/m/library-preload.json
    resources/sap/ui/core/library-preload.json
    resources/sap/ui/thirdparty/jquery-mobile-custom.js
    resources/sap/ui/core/themes/sap_bluecrystal/library.css
    resources/sap/m/themes/sap_bluecrystal/library.css
    resources/sap/ui/core/messagebundle_en.properties
    resources/sap/m/messagebundle_en.properties
    resources/jquery.sap.storage.js
    resources/sap/ui/core/themes/base/fonts/SAP-icons.ttf
    resources/sap/ui/core/themes/sap_bluecrystal/library-parameters.json
    resources/sap/m/themes/sap_bluecrystal/library-parameters.json
    resources/sap/ui/thirdparty/unorm.js
    resources/sap/ui/thirdparty/unormdata.js
    resources/sap/ui/core/themes/base/fonts/SAP-icons.eot
    de.pensware.ui5StocksApp/Component.js
    de.pensware.ui5StocksApp/manifest.json
    de.pensware.ui5StocksApp/view/Main.view.xml
    de.pensware.ui5StocksApp/view/Main.controller.js
    de.pensware.financeAPI/Component.js
    de.pensware.financeAPI/js/stockQuotesAPI.js
    NETWORK:
    *




Everything below CACHE MANIFEST defines all the OpenUI5 and app resources needed to run the app. All these files are fetched on the first start of the app and are then available for offline usage. **NETWORK: *** means that every network request not specified in CACHE MANIFEST will be sent directly to the network.

Component based design

The code related to fetching the stock quotes from yahoo is encapsulated into a faceless component.

This financeAPI component is loaded with the following code:


var ofinanceAPI = sap.ui.component( {name: "de.pensware.financeAPI" } )
var oStockQuotesAPI = ofinanceAPI.getStockQuotesAPI();




LocalStorage to persist data

Stock symbols and fetched data from yahoo finance api are stored in local storage for offline usage.

Model View Controller + light weight ViewModel

The Main.view.xml is XML format. The Main.controller.js instantiates a JSONModel and sets it with the name “localUIModel” to the view.


_createAndSetLocalUIModel : function () {
  this._localUIModel = new sap.ui.model.json.JSONModel();
  this._localUIModel.setData({
  symbols: [{symbol: "test", price: "489"}, {symbol: "MSFT", price: ""}],
  newSymbol: "",
  aMessages: [],
  listMode: sap.m.ListMode.None
  });
  this.getView().setModel(this._localUIModel, "localUIModel");
}



Every input the user makes or data the app wants to display is written into this model. This way the Main.controller.js makes no assumptions on how the data is displayed and the Main.view.xml can be changed without having to change javascript code.

This also makes the controller testable. An event handler like onToggleListMode is only modifying the “localUIModel” and that can be tested very easily.


onToggleListMode : function () {
  var sCurrentMode = this._localUIModel.getProperty("/listMode");
  if (sCurrentMode === sap.m.ListMode.None) {
  this._localUIModel.setProperty("/listMode", sap.m.ListMode.Delete);
  } else {
  this._localUIModel.setProperty("/listMode", sap.m.ListMode.None);
  }
}



The test:


QUnit.test("onToggleListMode function", function (assert) {
  var oLocalUIModelData = this._oCntrllr._localUIModel.getData();
  //initial mode is sap.m.ListMode.None
  assert.equal(oLocalUIModelData.listMode, sap.m.ListMode.None);
  this._oCntrllr.onToggleListMode();
  assert.equal(oLocalUIModelData.listMode, sap.m.ListMode.Delete);
  this._oCntrllr.onToggleListMode();
  assert.equal(oLocalUIModelData.listMode, sap.m.ListMode.None);
});



Injecting dependencies into controller for better testability

The stockquotes API object and the storage object are injected into the Main.controller.

This way the Main.controller can be instantiated with a mock version of the stockquotes API object for easy unit testing.


var oStockQuotesAPI = {
  fetchData: function () {
  return {
  fail: function () {}
  }
  }
};
var oStorage = jQuery.sap.storage(jQuery.sap.storage.Type.session);
this._oCntrllr = new de.pensware.ui5StocksApp.view.Main(oStockQuotesAPI, oStorage);

Links

UI5 offline application using ServiceWorker API

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

  1. Chandan Singh

    Hi Elmer,

    Awesome Blog.

    I am facing an issue while using the App Cache in Internet Explorer.

    Whenever the server tries to cache the resources in IE it gives me an error – “AppCache Fatal Error”.

    Please help. Thanks!

    Best Regards
    Chandan Singh

    (0) 
  2. Boghyon Hoffmann

    Hello Elmer,

    Thank you for your content. Unfortunately after almost a year, AppCache has been deprecated by ServiceWorkers API.

    I saw another great blog post of yours where you mentioned a UI5 app using ServiceWorkers API, but the app doesn’t seem to work offline anymore. Would you mind to update the UI5 ServiceWorkers app? (I’d like to know to how create a PWA using UI5 and for this, ServiceWorkers API is essential).

    Thank you.

    (0) 

Leave a Reply