SAPUI5 Best Practices
A collection of SAPUI5 best practices learned from actual projects and implementations.
You can also check tutorials and guides on my blog, genuineprogrammer for more!
- Following naming conventions
- Naming the project and namespace
- Keeping the project name and SAPUI5 ABAP repository name the same
- Keeping the project name and git repository name similar
- Following reverse-DNS for the project namespace
- Keeping the project namespace descriptive or contain abbreviations of the app
- Using base controllers
- Using parent controllers
- Exhausting models
- Reducing modules
- Reducing anonymous functions
- Using i18n over text in code
- Using correct odata types
- Using correct CRUD operations
- Using createKey for CRUD operations
- Using createEntry for create operations
Use hungarian notation for naming variable name and object properties:
Sample | Type |
---|---|
sId | string |
oDomRef | object |
$DomRef | jQuery object |
iCount | int |
mParameters | map / assoc. array |
aEntries | array |
dToday | date |
fDecimal | float |
bEnabled | boolean |
rPattern | RegExp |
fnFunction | function |
vVariant | variant types |
You can also refer to this in-depth naming convention as a reference. (TO FOLLOW)
Keep project name up to 15 characaters
. It will help you on your deployment to SAPUI5 ABAP Repository. SAPUI5 ABAP Repository has a limit of 15 characters for the new application name.
BAD:
Z_TESTING_APPLICATION
GOOD:
Z_TESTAPP
Same project name and abap repository name, makes searching in SICF
transaction easier.
SAP Web IDE Git only accepts lowercase alphanumeric characters and must not exceed 30 characters
.
Reverse-DNS identify resources quickly. It helps avoid naming collision and duplicates. It also organizes the applications in a modular manner. Also, try to keep the project namespace to 3 segments
.
BAD:
my.awesome.app.com
GOOD:
com.example.ztestapp
Keep namespaces readable and recognizable as much as possible. Use abbreviations to shorten the namespace.
BAD:
com.1.0.1.app.test
GOOD:
com.example.ztestapp
com.mycompany.timesheet
Catalog should be easy to be identified via name
FORMAT:
Z_<3-character SAP module>_C_<catalog name>
SAMPLE:
Z_HCM_C_ESS
Similar to catalog, should be identifiable via name
FORMAT:
Z_<3-character SAP module>_G_<catalog name>
SAMPLE:
Z_HCM_G_ESS
Semantic objects must represent entities and not actions.
Represents a business entity such as a customer, a sales order, or a product. Using semantic objects, you can bundle applications that reflect a specific scenario. They allow you to refer to objects in a standardized way, abstracting from concrete implementations of these objects.
You can either use semantic objects shipped by SAP, or create new semantic objects.
BAD:
#ZHCM_EXT_APP
#zHcmCreate
GOOD:
#SalesOrder
Actions are more specific to what the task being performed by the user.
BAD:
salesOrderActive
timesheetError
GOOD:
displayFactSheet
manageTimesheet
COMPLETE FORMAT:
<semantic object>-<action>?<semantic object parameter>=<value1>
In actual projects, it is recommened to set a fix SAPUI5 version. This assures the supported libraries are compatible and consistent to your development setup. For stand alone application verify the index.html
resource version.
For launchpad ready applications, verify the version in the app descriptor file or manifest.json
.
Also verify the project settings in SAP Web IDE, to match your systems version.
Targets and routes should match view file to easily track the flow of the navigation. Also provide the following as minimal settings for targets:
viewLevel
- sets heirarchy to the application views.transition
- the default transition behavior for the current target.bypass
- fail safe target for unmatched routes.
Route name should be descriptive by itself. Prefer plural form for routes if applicable.
BAD:
page1
itemDetail
GOOD:
home
itemDetails
Routing parameters should be url safe, stay away from unsafe characters as parameters:
"{", "}", "|", "\", "^", "~", "[", "]", and "`"
Routing parametes should be singular form
BAD:
itemDetails/{objectIds}
orders/{orderItems}
GOOD:
itemDetails/{objectId}
orders/{orderId}
Move reusable functions to higher scope. The recommended base controller contents as follows:
getRouter
getResourceBundle
getModel
setModel
onNavBack
Enhance existing controllers by using them as parent controllers, but do take note:
Note: The SAPUI5 controller extension concept does not use inheritance
Models allows you to write maintainable code. It also allows you to auto update control properties and bindings all at once. It also decouples the data to the presentation layer.
BAD:
var oText = this.getView().byId("text-field");
oText.setText("hello");
oText.setTextAlign("End");
oText.setBusy(true);
// ... update only the oText control
GOOD:
var oModel = this.getView().getModel();
oModel.setProperty("/message", "hello");
oModel.setProperty("/alignment", "End");
oModel.setProperty("/busy", true);
//... auto updates all controls with binding
Reduce response time and performance by using only what is needed by the application.
- Bootstraps - preload modules in
manifest.json
, the ones used throughout the application. constructor
andonInit
- dependencies loaded in thesap.ui.define
of the controller.- On-demand - Inline
sap.ui.require
, for Dialogs and rarely used elements.
Prefer callbacks as separate function for readability and extensibility.
BAD:
fnMyServiceCall: function() {
var oModel = this.getView().getModel("view");
oModel.read("/Orders", {
success: function(oResult, oResponse){
// do something
},
error: function(oError){
// output error
}
})
}
GOOD:
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
}
BAD:
onPressButton: function(){
MessageToast.show("hey! hey! hey!");
}
GOOD:
onPressButton: function(){
MessageToast.show(this.getResourceBundle().getText("message"));
}
Do not use Edm.Strings
to represent the following, etc.:
- Date use
Edm.Date
- Time use
Edm.Time
- Currency use
Edm.Decimal
- Flags (e.g. ABAP true, 'X') use
Edm.Boolean
- Do not use
odata.create
to delete and override existing entry, useodata.update
- Do not use
odata.read
,odata.create
for non-CRUD functionality like calculations and aggregations of results usefunction import
instead. - Do not use
odata.read
forfunction import
usecallFunction
var oHandle = oModel.callFunction("/GetProductsByRating", {urlParameters: {rating:3}});
oHandle.contextCreated().then(function(oContext) {
oView.setBindingContext(oContext);
});
Use createKey
to generate collection URLs and to pre-validate against the metadata
the existence of the collection.
BAD:
myODataModel.update("/Orders(123)");
GOOD:
var sPath = oModel.createKey("/Orders", {
OrderId: 123, // your dynamic key value
});
oModel.update(sPath /*,...*/);
Use createEntry
to instatiate new collection items for submission of entries.
// create an entry of the Products collection with the specified properties and values
var oContext = oModel.createEntry("/Products", {
properties: {
Id:99,
Name:"Product",
Description:"new Product",
ReleaseDate:new Date(),
Price:"10.1",
Rating:1
}
});
// binding against this entity
oForm.setBindingContext(oContext);
Always set the project to the base ESLint ruleset which you can find here or for OpenUI5.
Always document that adheres to jsdoc
, alternative link can be found here.
Refer to this Example for Defining a Class for the SAPUI5 standard controller or module documentation.