This project demonstrates how to develop an offline enabled OpenUI5 stock application using the AppCache API and LocalStorage.
You can try it out here: https://pensoffsky.github.io/OpenUI5-AppCache/index.html
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.
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.
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();
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);
});
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);