SAPUI5 Best Practices for Beginners — Part 2

Gin Rueda
6 min readOct 31, 2018

--

As a follow-up post from my “SAPUI5 Best Practices for Beginners — Part 1”, we’ll be focusing on source code level best practices for SAPUI5. In practice, having a well-structured project is just a starting point for a more robust application. The goal is to have a well-rounded project inside and out.

So today, we’ll be discussing some tips that you can implement in your source code. Do take note that these tips are not only applicable to SAPUI5 but in any project in general. Let me know what you think of these tips and if you like them, do share them with your colleagues.

Best Practices

1. Naming Variables

Always keep it simple and easy to understand.

Don’t:

var a;
var bFlagForAsynchrounousServiceCallWithCallbacks;

Not only that it’s pretty hard to read and maintain, you can actually misinterpret or forget what they really do in the first place.

It should be easy to relate to. Searchable by memory and one that you can describe to others without confusion.

Do:

var sCounter;
var oResponseData;

2. Avoiding global variables (members)

Exposing too many variables to the global scope can result in unintentional run time errors. Since members are accessible to the whole view or module, undeclared variables or variable with the same name can also affect the value of the globally scoped variable if not handled properly. In order to reduce the chances of having unwanted access to the variables, scope them to where they should belong.

Don’t

var iCounter=0;function incrementCounter(){
iCounter++;
}
function loopItems(){
// may not be executed due to global modification
if(iCounter === 0){
// for ....
}
}

3. Using SAPUI5 models

Since SAPUI5 by default conforms to the MVC pattern, why not use models extensively?

Models can be very powerful in terms of manipulating views. It also reduces the need for ids for control. By using models we can manipulate the view by accessing properties and modifying the values. Rather than accessing the control and manipulating each property by hand.

XML View

<!-- XML View -->
<Panel>
<!-- Text can be controlled via model manipulation -->
<Text text="hello world!" visible="{pageModel>/textHidden}" />
<Button
text="Show text!" press="onPressButton"/>
</Panel>

Controller

// controller.js ...onInit: function(){
// Declare the page model
var oModel - new JSONModel({
"textHidden": true
});
// apply model to page
this.getView().setModel(oModel, "pageModel");
},
onPressButton: function(){
var oModel = this.getView().getModel("pageModel");
// show the text by manipulating the model
// instead of the control
oModel.setProperty("/textHidden", false);
}

It decouples the logic to the presentation layer by only interacting with the model. This keeps the XML views clean and dedicated to presenting data.

I usually used this approach for toggling visibility, drop-down selection, busy loading, dynamic labels and more.

4. Utilizing internationalization (i18n)

Aside from being a translation file for different languages, i18n can help reduce the number of formatter or utility functions for your application.

Using i18n, you can easily build formatted string via parameter passing. This can be done using the controller or a bundles in function, but I recommend doing it via XML view:

Controller:

// Controller.jsonInit: function(){
// Declare the page model
var oModel = new JSONModel({
"firstName": "John",
"lastName": "Doe"
});
// apply the model
this.getView().setModel(oModel,"view");
}

i18n.properties:

# view translations
welcomeMessage=Welcome Back!
# will be pre-formatted by parameter sequence passed
helloMessage=Hi {0} {1}!

XML View:

<!-- firstName will be placed to {0} in i18n -->
<!-- lastName will be placed to {1} in i18n -->
<Text text="{parts: [
'i18n>helloMessage',
'view>/firstName',
'view>/lastName'
], formatter: 'jQuery.sap.formatMessage'}"/>

Output:

Hi John Doe!

Now, what happens if we switch the parameter sequence in i18n?

# view translations
welcomeMessage=Welcome Back!
# will be pre-formatted by parameter sequence passed
helloMessage=Hi {1} {0}!

The output will be adjusted according to the definition:

Hi Doe John!

As you can see, this reduces the number of utility files needed. You can just easily define the structure in the i18n file and build string on the fly. It also keeps the controller clean and the XML file declarative.

5. Using comments properly

Comments are always helpful, not only for you but to any succeeding developer that will support your application. On the other hand, do not overdo the documentation. Comment only what is needed.

JSDoc is very handy in documenting your source code:

/**
* Increment a counter
* @param {number} incrementValue How much value to increase
* @returns {number}
*/
fnIncrementValue: function(incrementValue) {
var value = this.maxValue + incrementValue;
return value;
}

6. Reducing modules

There are several ways to load modules. Each method is intended to reduce response time and performance by using only what is needed by the application.

  • Bootstraps — modules loaded in manifest.json are the ones used throughout the application.
  • Constructor and Init — dependencies loaded in the sap.ui.define of the controller file are used for controller-wide dependencies.
  • On-demand — these are inline sap.ui.require, for example, Dialogs. Used them for rarely used elements and libraries in your view.

8. Avoiding inline functions

Yes, inline functions are very convenient and at times you can reduce lines of code with it. But maintaining them, in the long run, can result in bad results. It is recommended to modularize your function and cache them as much as you can. Especially for callback functions, you can reuse callback function by declaring them formally.

Avoid nesting function

fnMyServiceCall: function() {
var oModel = this.getView().getModel("view");
oModel.read("/Orders", {
success: function(oResult, oResponse){
// do something
},
error: function(oError){
// output error
}
})
}

to this

fnMyServiceCall: function() {
var oModel = this.getView().getModel("view");
oModel.read("/Orders", {
success: this.fnSuccessCallback,
error: this.fnErrorCallback
})
},
fnSuccessCallback: function(oResult, oResponse){
// do something
},
fnErrorCallback: function(oError){
// output error
}

This makes the sequence of operation on oModel.read() easier to understand. We can also reuse these callback functions to other service calls since it’s now available at the module level. Always remember to break functions into a single unit of purpose.

One function one purpose.

9. Using XML views

Remember from “Part 1” that XML views are highly favored due to declarative format. Having XML views also helps you picture the layout as you would see it in the actual browser. You can easily spot in an XML view if the layout is becoming too complex, which result to slow DOM performance.

Aside from decoupling logic to the presentation layout, XML views also help bind data to a control much easier. By default, SAPUI5 will automatically attach event handlers for you and refresh data if there are updates from the server. Busy loading is also covered since the control has binding via XML views.

10. Avoiding hard-coded IDs

One of the common errors developers may encounter in SAPUI5 is the “duplicate id error”. The root cause of this is hard-coded ids in the view file. If you reattach or reuse a view or fragment to a different part of the page, more likely than not you might encounter this error. This is because SAPUI5 will try to reinsert the control into the DOM, and found out that another control already took the id before.

Though ids are very useful for getting the control instance, you can easily update controls via the control model. You won’t need to remember the id of that specific control, rather focus on the data manipulation. SAPUI5 will automatically notify all control that has binding to that model for you.

11. Reusing elements

In relation to having reusable controls, leverage fragments. Fragments highly increase the re-usability and help you insert controls even at run time. If your application has reoccurring control parts, you can just declare a fragment then reuse them anywhere needed.

Fragments are also cached once they are instantiated, which will speed up your application response moving forward.

Summary

In conclusion, always review these pointers since it will help your application in terms of maintainability and performance. It’s also good to build a habit around these principles since you can adopt some of them in other programming languages.

Review your code and always test.

Find this tutorial helpful? Let me know what you think, leave a comment below, or follow me or my channel. Cheers!

--

--

Gin Rueda

Tech Consultant. Developer. Artist. SAPUI5. SAP Fiori. Laravel.