Skip to Content
Technical Articles

Create SAPUI5 Applications with Google Firebase

Hi there!

Also a passion for SAPUI5 and Google Firebase?

Then you just hit the right blog!

Back then at university I worked a lot with Google Firebase to Create Web and Native applications.

Since two years I’m spending my time working with SAP-Services. Especially with the SAPUI5 Framework in the SAP Full-Stack WebIDE.

There is no way I would switch the SAPUI5 Framework or the SAP Full-Stack WebIDE back for another framework or editor. Cause they rock!

But like we all know everything keeps evolving… so I tried to stay tuned and I started wondering…

Why not bringing 2 of my favorites together?

Well this is is exactly what I did!

Here you can find some other blogs where I used Firebase services in SAPUI5 Applications:

SAPUI5 FIREBASE BLOG SERIES:

Create SAPUI5 Applications with Google Firebase (this blog)
SAPUI5 Applications with Firebase Anonymous Authentication
SAPUI5 Applications with Firebase Cloud Messaging

But let’s continue with this one for the moment.

Using the Firebase Cloud Firestore Database as back-end together with the SAPUI5 Framework to create a Realtime Web Application.

So no polling data with setInterval functions. But real time data provided by the back-end.

In this blog I will show you how to implement Firebase into your UI5 Application. By creating, updating and deleting data in the back-end which will trigger automatic data updates in your application.

Let’s get started!

 

1. Initialize and Setup your Firebase Project 

 

The first thing you want and need to do, is create a Firebase project.

This can be done in the Firebase Console.

More information about Firebase.

 

1.1 Here is on how to get started on with Firebase on the web.

 

1.2 Here is on how to get started with Cloud Firestore on the web.

 

1.3 Cloud Firestore Security-Rules

Use the following security-rules only in a test-environment. We need these rules so we can consume our data from the Firebase Cloud Firestore Database into our SAPUI5 Application.

// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this rule set in production; it allows
// anyone to overwrite your entire database.
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}

 

After the development we close our database read and write access for everyone except for our authenticated users.

// Allow read/write access on all documents to any user signed in to the application
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth.uid != null;
    }
  }
}

 

Or we close the database for everyone.

// Deny read/write access to all users under any conditions
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

 

 

1.4 Add some test data to the Cloud Firestore database

So next we want to populate our database with a Collection of Shipments.

Some Documents that represent real Shipments.

With some Properties for a Shipment.

Add as much Shipments (documents) as you like.

 

1.5 Comparison between OData and Firebase Cloud Firestore.

OData Firebase
Odata Collection Firebase Collection
Odata Entry Firebase Document
Odata Property Firebase Property

 

 

2. Initialize and Setup your SAPUI5 Application 

 

Let’s keep this rocking and jump into the SAPUI5 World!

Of course we will work in our beloved SAP Full-Stack WebIDE.

 

2.1 Select a template to start from

For this demo app we will start from a UI5 template application.

 

2.2 Add the core Firebase JS SDK

We add the the core Firebase JS SDK to our index.html file. This along with our Cloud Firestore JS SDK.

Add the following Firebase imports after the first script-tag.

<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/6.1.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/6.1.0/firebase-firestore.js"></script>

 

Your index.html file should look like this.

 

2.2 Create a Firebase.js file

Next we create a Firebase.js file at the root-level of our webapp folder.

In here we will store our Firebase-config and we will initialize Firebase for our app. Finally we expose our Firebase logic in the form of a JSON-model.

As you can see the Firebase-config gathered from the Firebase-console, is pasted inside our Firebase.js file.

We create our own initializeFirebase function which will initialize Firebase, along with Cloud Firestore in the form of a JSON-model.

sap.ui.define([
	"sap/ui/model/json/JSONModel",
], function (JSONModel) {
	"use strict";
	
	// Firebase-config retrieved from the Firebase-console
	const firebaseConfig = {
		apiKey: "YOUR-API-KEY",
		authDomain: "YOUR-AUTH-DOMAIN",
		databaseURL: "YOUR-DATABASE-URL,
		projectId: "YOUR-PROJECT-ID",
		storageBucket: "YOUR-STORAGE-BUCKET,
		messagingSenderId: "YOUR-MESSAGE-SENDER-ID",
		appId: "YOUR-APP-ID"
	};

	return {
		initializeFirebase: function () {
			// Initialize Firebase with the Firebase-config
			firebase.initializeApp(firebaseConfig);
			
			// Create a Firestore reference
			const firestore = firebase.firestore();
			
			// Firebase services object
			const oFirebase = {
				firestore: firestore
			};
			
			// Create a Firebase model out of the oFirebase service object which contains all required Firebase services
			var fbModel = new JSONModel(oFirebase);
			
			// Return the Firebase Model
			return fbModel;
		}
	};
});

 

2.3 Call and Initialize Firebase in the Component.js file and set it as a model

Import the Firebase.js file in the sap.ui.define method. Call the initialize function and set it as a model with the name ‘firebase’. From now on our Firebase model is set and ready to be used. Your Component.js file should look like this.

sap.ui.define([
	"sap/ui/core/UIComponent",
	"sap/ui/Device",
	"sap/firebase/SAP-Firebase-Connect/model/models",
	"./Firebase"
], function (UIComponent, Device, models, Firebase) {
	"use strict";

	return UIComponent.extend("sap.firebase.SAP-Firebase-Connect.Component", {

		metadata: {
			manifest: "json"
		},

		/**
		 * The component is initialized by UI5 automatically during the startup of the app and calls the init method once.
		 * @public
		 * @override
		 */
		init: function () {
			// call the base component's init function
			UIComponent.prototype.init.apply(this, arguments);

			// enable routing
			this.getRouter().initialize();

			// set the device model
			this.setModel(models.createDeviceModel(), "device");
			
			// Import Firebase in the sap.ui.define
			// set the firebase model by calling the initializeFirebase function in the Firebase.js file
			this.setModel(Firebase.initializeFirebase(), "firebase");
			
		}
	});
});

 

2.4 Prepare your Main.view.xml file

In our view we want to show our shipments: shipment id, origin, destination and status.This in a table with column list items.

But let’s do our-self a favor and remind our-self about the Firebase security-rules. We don’t want to forget to close the public read and write access at the end of our demo test phase.

Here fore we create a little message strip that will remind us to open and close the security rules for read and write access.

<MessageStrip text="{i18n>fbSecurityRules}" type="Warning" showIcon="true" showCloseButton="true" class="sapUiMediumMarginBottom"/>

 

So now that we created our own personal reminder message strip we can add our table to the view.

We bind our root path of shipments to the items aggregation of our table. This way we can bind our shipment properties in the respective column list item.

We bind our title and column name to the correct i18n keys and last but not least the values into the Text controls.

<Table id="shipmentTable" items="{/shipments}">
	<headerToolbar>
		<Toolbar>
			<content>
				<Title text="{i18n>Shipments}" level="H2"/>
			</content>
		</Toolbar>
	</headerToolbar>
	<columns>
		<Column>
			<Text text="{i18n>ShipmentId}"/>
		</Column>
		<Column>
			<Text text="{i18n>Origin}"/>
		</Column>
		<Column>
			<Text text="{i18n>Destination}"/>
		</Column>
		<Column>
			<Text text="{i18n>Status}"/>
		</Column>
	</columns>
	<items>
		<ColumnListItem>
			<cells>
				<Text text="{code}"/>
				<Text text="{origin}"/>
				<Text text="{destination}"/>
				<ObjectStatus text="{status}" state="{= ${status} === 'Shipped' ? 'Success' : ${status} === 'Missing' ? 'Warning' : ${status} === 'Preparing' ? 'Information' : 'Error'}" icon="{= ${status} === 'Shipped' ? 'sap-icon://accept' : ${status} === 'Missing' ? 'sap-icon://status-critical' : ${status} === 'Preparing' ? 'sap-icon://begin' : 'sap-icon://status-negative'}"/>
			</cells>
		</ColumnListItem>
	</items>
</Table>

 

This way our table will be populated once we receive the data from the Cloud Firestore.

We can add some nice UI5 features to our table, by using the ObjectStatus control.

This way we can show the shipment status with a color (state) and a symbol (icon).

But how to achieve this? Please not through a formatter, a formatter in here would be (in my opinion) an unnecessary implementation.

So let’s use Expression Binding.

More information about Expression Binding at SAPUI5 Demo Kit.

 

How to read this state expression binding for the state (color) property of the Objectstatus?

If the received value: ${status}

Shipped Success
Missing Warning
Preparing Information
Everything else (so also Damaged) Error

If Status equals Shipped then Success

Else if Status equals Missing then Warning

Else if Status equals Preparing then Information

Else Error

state="{= ${status} === 'Shipped' ? 'Success' : ${status} === 'Missing' ? 'Warning' : ${status} === 'Preparing' ? 'Information' : 'Error'}"

 

Same logic is applied on the icon of the Objectstatus, with icon values of course.

We now finished the adjustments and creation of the Main.view.xml file.

 

2.5 Populate your i18n file with the key-values

You can copy paste the following key-values for your i18n model. We used this in our text binding in the Main.view.xml.

title=SAP-Firebase Connect App
appTitle=SAP-Firebase-Connect
appDescription=App Description

fbSecurityRules=Don't forget to turn on and off the read permission again in the Firebase Firestore security rules.

Shipments=Shipments
ShipmentId=Shipment id
Origin=Origin
Destination=Destination
Status=Status

 

2.6 The Main.controller.js file.

Now what will happen in the Main.controller.js file?

  1. Get our Firebase model, with all the services we added to it in the Firebase.js file.
  2. Create a Firestore reference.
  3. Create a collection reference to the shipments collection.
  4. Initialize an array for the shipments of the collection as an object.
  5. Create and set the created object to the the shipmentModel and set it to the view.
  6. Get single set of shipments.

This will all be done in the onInit function of our Main.controller.js. Your onInit function should look like this.

onInit: function () {
	// Get the Firebase Model
	const firebaseModel = this.getView().getModel("firebase");
			
	// Create a Firestore reference
	const firestore = this.getView().getModel("firebase").getData().firestore;
	// Create a collection reference to the shipments collection
	const collRefShipments = firestore.collection("shipments");

	// Initialize an array for the shipments of the collection as an object
	var oShipments = {
		shipments: []
	};
			
	// Create and set the created object to the the shipmentModel
	var shipmentModel = new JSONModel(oShipments);
	this.getView().setModel(shipmentModel);

	// Get single set of shipments once
	this.getShipments(collRefShipments);
},

 

Add this point we still need to create our getShipments function.

getShipments: function (collRefShipments) {
	collRefShipments.get().then(
		function (collection) {
			var shipmentModel = this.getView().getModel();
			var shipmentData = shipmentModel.getData();
			var shipments = collection.docs.map(function (docShipment) {
						return docShipment.data();
					});
			shipmentData.shipments = shipments;
            this.getView().byId("shipmentTable").getBinding("items").refresh();
	}.bind(this));
}

 

This function holds the (in the onInit created) shipments reference as parameter.

On this collection we will perform a get call which will return all our shipments (Documents).

Once the call is finished we received our shipments in the collection parameter.

At this point we want to get our shipment model and retrieve the data from it.

Next we map our collection (result) so we can retrieve the data from a shipment (Document).

This with the data() function from Firebase.

Once this is done we add our result (shipments) to our shipmentData and we refresh the binding of the items in our table.

 

2.7 Let’s run the application and check the result.

When we launch the application we get the following result. Looks nice right?

Our table populated with our data, just the way it should be. This using the UI5 Framework.

 

Nothing special so far right? Let’s add the magic!

 

2.7 Add a real-time listener for add, modify and deletion operations in the shipment collection.

We saw that the data is fetched once from our shipment collection and it is displayed in our table.

What if, it is so important that the shipments need to be updated immediately?

Well then we add the real-time listeners.

The first thing we want to do is comment the getShipments function and add the getRealTimeShipments function in the onInit function of our controller.

Again passing our shipment collection reference.

// Get single set of shipments once
//this.getShipments(collRefShipments);

// Get realtime shipments
this.getRealTimeShipments(collRefShipments);

 

Next we want to implement our getRealTimeShipments function.

This function looks like this, little busy function right?

getRealTimeShipments: function (collRefShipments) {
	// The onSnapshot the keep the data up to date in case of added, 
	// modified or removed data in the Firestor database
	collRefShipments.onSnapshot(function (snapshot) {
		// Get the shipment model
		var shipmentModel = this.getView().getModel();
		// Get all the shipments
		var shipmentData = shipmentModel.getData();
				
		// Get the current added/modified/removed document (shipment) 
                // of the collection (shipments)
		snapshot.docChanges().forEach(function (change) {
			// set id (to know which document is modifed and
                        // replace it on change.Type == modified) 
			// and data of firebase document
			var oShipment = change.doc.data();
			oShipment.id = change.doc.id;

			// Added document (shipment) add to arrat
			if (change.type === "added") {
				shipmentData.shipments.push(oShipment);
			} 
			// Modified document (find its index and change current doc 
                        // with the updated version)
			else if (change.type === "modified") {
				var index = shipmentData.shipments.map(function (shipment) {
						return shipment.id;
					     }).indexOf(oShipment.id);
				shipmentData.shipments[index] = oShipment;
			} 
			// Removed document (find index and remove it from the shipments array)
			else if (change.type === "removed") {
				var index = shipmentData.shipments.map(function (shipment) {
						return shipment.id;
					    }).indexOf(oShipment.id);
				shipmentData.shipments.splice(index, 1);
			}
		});
				
		//Refresh your model and the binding of the items in the table
		this.getView().getModel().refresh(true);
		this.getView().byId("shipmentTable").getBinding("items").refresh();
	}.bind(this));
}

 

Let’s split it up into pieces.

1. We want to listen for changes on all our documents in our collection shipments.

We immediately bind ‘this’ to our function so we have a this reference later to work with.

// The onSnapshot creates a listener to our collection in this case
collRefShipments.onSnapshot(function (snapshot) {
}.bind(this));

 

2. In our onSnapshot function we get our shipmentModel and our shipments.

// Get the shipment model
var shipmentModel = this.getView().getModel();
// Get all the shipments
var shipmentData = shipmentModel.getData();

 

3. We do NOT want our full shipment collection again when changes occur.

So we add a document listener that will return a specific document in the onSnapshot function.

// Get the current added/modified/removed document (shipment) of the collection (shipments)
snapshot.docChanges().forEach(function (change) {
});

 

4. When we first load our application, the shipments (Documents) id is set.

By doing this, we later have an easy reference to our shipment (Document) when its changed.

We can set it here since the application will pass through the added part on loading the data.

// set id (to know which document is modifed and replace it on change.Type == modified) 
// and data of firebase document
var oShipment = change.doc.data();
oShipment.id = change.doc.id;

 

5. When a shipment is added in the Cloud Firestore the type of the Document is added.

So we push this document into our shipment array.

// Added document (shipment) add to arrat
if (change.type === "added") {
	shipmentData.shipments.push(oShipment);
} 

 

6. If a shipment (Document) is modified the we will look it up in our shipment array.

This is where the earlier placed document id comes in handy. We search based on this id.

The returned index is used to replace the old shipment with the new one.

// Modified document (find its index and change current doc with the updated version)
else if (change.type === "modified") {
	var index = shipmentData.shipments.map(function (shipment) {
			    return shipment.id;
		    }).indexOf(oShipment.id);
	shipmentData.shipments[index] = oShipment;
} 

 

7. The same logic is applied for the deletion of a shipment in the back-end.

We look up the index of the deleted shipment and delete it from our array.

This using splice and NOT the delete object from array. 

Using the delete object would clear the values from the object (list item in our table),

but still an empty list item would be visible in our table.

// Removed document (find index and remove it from the shipments array in the model)
else if (change.type === "removed") {
	var index = shipmentData.shipments.map(function (shipment) {
				return shipment.id;
		    }).indexOf(oShipment.id);
	shipmentData.shipments.splice(index, 1);
}

 

8. As last we hard refresh our view’s model and we refresh the items binding of our table.

This outside our docChanges function.

//Refresh your model and the binding of the items in the table
this.getView().getModel().refresh(true);
this.getView().byId("shipmentTable").getBinding("items").refresh();

 

Alright! We finished the full real-time implementation of our controller.

Let’s see this in action!

 

 

3. Demo action time!

 

There will be 4 steps in this demo video.

  1. Open the UI5 Applications.
  2. Modify data in the back-end and see the UI5 App responding to it.
  3. Add data in the back-end and see the UI5 App responding to it.
  4. Delete data in the back-end and see the UI5 App responding to it.

 

Awesome isn’t it? This with the SAPUI5 Framework! Love it!

 

 

4. Recap time, what did we learn?

 

In this blog I went over a lot of functionalities of Both UI5 and Firebase.

So here are some key takeaways:

  1. The SAPUI5 Framework is still our way to go in developing apps.
  2. Our preferred IDE is the SAP Full-Stack WebIDE with no doubt.
  3. We can consume Google Firebase Services in our SAPUI5 Applications.
  4. No setInterval javascript functions or other polling methods are used.
  5. Use of Expression binding where possible over formatters.
  6. Firebase security rules are important!

 

Talking about security rules…. You closed your database again with the correct security rules? 😉

 

Both of my favorites work together in an awesome integrated way!

What do you think about it? Worth to give it a try?

 

Thanks for reading my blog about “Create SAPUI5 Applications with Google Firebase“.

I hope you found it interesting!

 

See you next time!

 

Kind regards,

Dries

 

11 Comments
You must be Logged on to comment or reply to a post.
  • Hi Dries,

    nice article that brings two of my favorite products together, even though I don’t agree with you regarding your opinion about WebIDE. It’s a great editor but depending on the requirements there are better ones.

    Thanks Helmut

    • Hi Helmut,

      Thank you for your reaction and happy to hear you share the same interests!

      Regarding the WebIDE, there are indeed other good editors that serve the case depending the requirements like you said. Totally agree on that.

      Kind regards,

      Dries

  • Hi Dries Van Vaerenbergh,

    i have followed each steps and when i try to run the application it is showing that firebase js resource is not loading so can you just tell me what might be the issue and can you share the git hub link for this application.

    • Hi Manohar,

      I was able to reproduce your error.

      I think your problem is situated in the Component.js file.

      I displayed my whole Component.js file in the blog including the following:

      sap.ui.define([
      	"sap/ui/core/UIComponent",
      	"sap/ui/Device",
      	"sap/firebadse/SAP-Firebase-Connect/model/models",
      	"./Firebase"
      ], function (UIComponent, Device, models, Firebase) {

      This cannot be copy pasted fully. You have to adjust the following line:

      sap/firebase/SAP-Firebase-Connect/model/models

      your/namespace/your-app-name/model/models

      You can find yours easily in the manifest.json for example: (change the dots in the namespace to / in the component.js)

      I think this is the problem. Could you check this and let me know?

      Good luck!

      Kind regards,

      Dries

      Ps: Nice you are trying it out!

       

       

  • I have always been working in SAP/ABAP world, and some time ago I have been spending 1 year developing SAPUI5 Apps and I did not know these kind of databases (we always use SAP as Backend and the SAP Gateway for Odata).

    Honestly, I loved what you showed us, and your explanation is very very clear and well explained.

    Thanks for let us know how to combine these two worlds Dries!

    Looking forward more Blogs from you!!

    • Hi Daniel,

      It is really nice to hear that! Thank you a lot!

      Happy to hear i was able to explain it in a proper way and that you like the idea of combining them.

      More blogs out now and more will follow.

      Kind regards,

      Dries