Design Best practice

This document is intended to list our combined project experience together with basic design guidelines to give beginners and advanced Neptune DXP - SAP Edition developers guidance on how to design and structure your app(s) with the Neptune DXP - SAP Edition.

This is a best practice guide for app design with Neptune DXP, although alternative approaches may be taken. Following these recommendations will improve app effectiveness and user experience.

As a start we would like to emphasize the following basics:

  • Single point of entry is the Neptune DXP - SAP Edition Cockpit, which is the home page and central location of all DXP - SAP Edition services.

  • The tiles on the launchpad represent navigation anchors to the individual apps. By selecting a tile, users navigate to the corresponding app. It is also possible to integrate legacy UI technology through such tiles.

  • With a launchpad, it is possible to create an app ecosystem in which apps can call and open each other and pass data. A launchpad is configured in the Launchpad service in the Cockpit. You can host multiple launchpads on one backend server. On each app in every launchpad all existing SAP user roles of your SAP system can be applied.

  • It is also possible to deploy and run each Neptune DXP - SAP Edition app individually and standalone.

  • We recommend designing all UI5 apps stateless.

  • We recommend designing your apps as split-apps, based on the sap.m.SplitApp control. The following design best practices are a recommendation and do not necessarily include all relevant guidelines for a project.

App settings

  • Neptune is utilizing SAP UI5 as the default HTML5 GUI framework for apps. Even though it is technically possible to use any HTML GUI framework, we recommend basing your Neptune applications on the UI5 framework.

  • We recommend using the standard Belize theme by default. Design adjustments can be added by applying custom CSS properties directly in the App Designer.

  • We recommend defining the Title/Group attribute in your app settings as this is the wording that is displayed on the browser tab.

  • It is Neptune and SAP Fiori best practice to design all UI5 apps stateless.

App basics

  • Every app should start with the sap.m.Shell control, which is typically named oShell.

  • As sub-nodes to the App/SplitApp control, it is recommended to define a set of sap.m.Page controls that determine the needed screens of your app. Hierarchically, all pages should be placed at the same level. It is possible to navigate from one page to another throughout the app.

  • The page control should be the first sub-node of your App/SplitApp control. It is the starting page which is displayed when the app starts.

  • If you are adding a SplitApp template, you need to specify the position parent-property in the attribute section of your page controls. You have to define if a page is shown in the Master or the Detail section of your SplitApp.

  • It is recommended to place all kinds of assisting controls that you need for your app but never want to display under Resources.

  • It is recommended to define a oPageDialogs where you can place all kinds of UI5 dialogue controls that are shown in your app. If you place them all on this page, the next developer knows where to find the pop-up dialogues in your HTML5 hierarchy.

folder structure

Naming conventions

  • Every object of an app must have a unique name.

  • We recommend the camel case notation: starting lowercase and using uppercase letters for all leading characters of the composite name.

  • It is UI5 best practice to start every object name with a lowercase o for the object. Neptune DXP - Open Edition only uses the o notation on Pages, App/SplitApp, and Shell control.

  • We recommend the following naming composition: [o] + Obj + Purpose + [Action]

  • In the HTML5 hierarchy, Pages should be the leading controls on naming.

  • As an example, if you design a page with the name oPageCustomerData, any sub-node to this page should follow the following naming:

    • sap.m.Table: oTabCustomerData

    • sap.m.Button: oButCustomerDataSave

    • sap.m.Button: oButCustomerDataBack

  • Rule of thumb: Define a naming convention at the beginning of a project and do not change it.

  • Do not just use Ui5 names with numbers for your objects.

  • Name your sap.m.Shell control oShell.

  • Name your sap.m.App/SplitApp control oApp.

Look and feel

  • We recommend following the basic SAP Fiori Design Guide when designing UI5 apps with Neptune. As a rule, the design of your app should be based on sap.m.Page as your primary design container.

  • Every page should include a header section.

  • Every page should include a footer section.

  • All process-specific design, for example, forms, tables, tabs, should be placed between the header and footer of a page.

  • The necessary process triggers, like buttons to save, cancel, submit, should be placed in the right section of the footer.

  • Back buttons should be placed in the left section of the page header or footer. It is important to stay consistent throughout your app(s).

  • In a SplitApp environment:

    • The master page should be the leading function, providing, for example, a list of (searchable) items, or an input form to define or search for datasets, or a list of subfunctions.

    • The detail page should display process or data details and functional triggers, for example, information on a specific dataset selected on the master page, sub-items of a dataset, or input fields to create a new dataset.

    • Both sections should have a footer, displaying buttons to trigger further actions.

  • Buttons should follow a basic color concept, which can be set via the property type:

    • Blue (type: Emphasized): Core function trigger of a page, for example, Search, Submit. In general, used to emphasize a particular button object in contrast to no styled buttons on the same footer or toolbar.

    • Green (type: Accept): Positive function trigger, used mostly in combination with a negative trigger, for example, Save or Delete.

    • Red (type: Reject): Negative function trigger, used mostly in combination with a positive trigger, for example, Decline or Approve.

    • None (type: default/none): Used for standard functions. Button blends in with footer/toolbar, for example, Settings.

Backend calls

To successfully design an API call, you need to define the following parts:

  • Bind your backend attributes to the corresponding UI5 controls.

  • Define your Ajax ID for the backend call at one of the bound controls:

    • In online scenarios, we recommend that you use the main receiving UI5 control to define the Ajax ID (for example, if you want to fetch an internal table from the backend or define the corresponding Ajax ID at the UI5 table control where you have bound that internal table).

    • In offline scenarios, we recommend using sap.m.Ajax control to define the Ajax ID for your backend calls. In most offline cases, your app only consists of two Ajax IDs (backend calls): SYNC and SAVE.

  • If you want to send or receive more than one data model, use the Additional Model Send/Receive button next to your Ajax ID.

  • Implement corresponding backend code in your ABAP class based on the incoming Ajax ID.

  • Based on the definition of your Ajax ID (for example, at UI5 table control tabMyTable), Neptune automatically creates an anonymous function that can be used to trigger the backend call via a javascript function call. This function always uses the following naming convention: getOnline + nameOfUI5ObjectWhereAjaxIDisDefined(). In our example, the functions name are getOnlinetabMyTable().

  • The getOnline function can be used throughout the app, for example, in button press events or in the Init script.

  • When calling the backend, always enable the busy mode of your app so that the user cannot continue until the server has answered or the call has failed:

// enable busy state
oApp.setBusy(true);

// trigger backend call
getOnlinetabMyTable();
  • Make use of the AjaxSuccess and AjaxError events.

    • AjaxSuccess: When the server answers with an expected result, the AjaxSuccess event at the UI5 control with your Ajax ID is triggered automatically. We recommend making use of this event in order to handle further process control after fetching data from the backend. This prevents wrong process control on the client-side if the server does not answer or the connection is broken during a call. Typical examples of needed client-side code in the AjaxSuccess event are disabling the busy state, navigation, and further data processing/updates. Below you find a common AjaxSuccess coding example:

// handle new data coming from backend
myDataHandler();

// navigate to next detail page
oApp.toDetail(myDetailPage);

// disable busy state
oApp.setBusy(false);
  • AjaxError: The AjaxError event should always be implemented together with the AjaxSuccess event. Implementing the AjaxError event prevents wrong process control on the client-side if the server does not answer or the connection is broken during a call. For example, if you trigger a server-side search call, you do not want to show an empty result list if the server is down, the ABAP logic dumps, or connection is lost. Correct process-handling would be to let the user know that the server did not respond. Below you find a common AjaxError coding example:

// disable busy state
 oApp.setBusy(false);

// show error toast
jQuery.sap.require("sap.m.MessageToast");
sap.m.MessageToast.show(txtTranslateAjaxError.getText());

Client-side scripting

  • In order to define custom Javascript code, we recommend using HTML5.ScriptCode controls. Store them under Resources.

  • For all code that should run initially when starting the app, create a ScriptCode control named Init. Here is an example of a typical init script:

// BeforeDisplay if (sap.n) {
 sap.n.Shell.attachBeforeDisplay(function() {
       // place your code here
 });
}

// InitLoad sap.ui.getCore().attachInit(function() {
    setTimeout(function() {
     // Rerender App
     oApp.rerender();
      // place your code here
}, 200);
});

// No Launchpad -> Hide navigation button
if (typeof AppCache === "undefined") {
    butBackMaster.setVisible(false);
}
  • For all custom javascript functions, create a ScriptCode control named Functions.

  • For all PhoneGap event implementations, create a ScriptCode control named PhonegapEvents.

ABAP class

  • The app-corresponding backend class must implement the /NEPTUNE/IF_NAD_SERVER interface.

  • Using UI5, the only applicable handling method is HANDLE_ON_AJAX.

  • In HANDLE_ON_AJAX, we recommend to only implement a single case statement based on input parameter AJAX_ID to redirect to the corresponding private methods of the class.

  • All attributes that are used for binding in NAD need to be declared public.

  • Attributes for binding can be flat structures or internal tables.

  • Attributes can be based on local structures or data dictionary.

  • Define small and lean private methods.

  • We recommend the usage of BAPIs to read/write data.

  • Standard ABAP coding conventions apply.

Neptune launchpad design approach

  • Define apps with one functional purpose.

  • Rule of thumb: If you can’t decide on a name, your app is too big.

  • Call apps from apps using AppCache.Load functions.

  • Define lean data interfaces between connected apps.

  • Best case: Your app just needs one key or file when opened from another app.

  • Define and use core apps and open them as dialogues (for example, Neptune PDF Viewer App).

  • Use the Neptune notifications client app inside your Launchpad to push and receive desktop notifications.

  • When coding Launchpad-specific functionality, always check first if the sap.n namespace is available to prevent errors when apps are running standalone:

// check if running in Launchpad
 if (sap.n) {

// place your Launchpad-specific code here
}

Best practice samples

In order to experience our best practices in action, please visit the Neptune Knowledge Center