Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
Showing results for 
Search instead for 
Did you mean: 
Developer Advocate
Developer Advocate
This is a searchable description of the content of a live stream recording, specifically "Episode 16 - Getting to a basic frontend with Fiori Elements, and sandbox launchpad" in the "Hands-on SAP dev with qmacro" series. There are links directly to specific highlights in the video recording. For links to annotations of other episodes, please see the "Catch the replays" section of the series blog post.

This episode, titled "Getting to a basic frontend with Fiori Elements, and sandbox launchpad", was streamed live on Wed 03 Apr 2019 and is approximately one hour in length. The stream recording is available on YouTube.

Below is a brief synopsis, and links to specific highlights - use these links to jump directly to particular places of interest in the recording, based on 'hh:mm:ss' style timestamps.

Brief synopsis

Following on from the previous episode broadcast from the SAP CodeJam in Frankfurt, we continue moving towards a first UI using a sandbox Fiori launchpad and a basic Fiori elements app driven by a small set of annotations.

00:04:51: A few announcements - on SAP CodeJam events (find out more at the SAP Community and Developer Events page), on SAP Inside Tracks and stickers! I have some SAP Cloud Application Programming Model stickers as well as some stickers - if you would like a couple, please join the next live stream and let me know.

I also mentioned the Awesome Developer Streams page which lists all sorts of different developers who also stream live - definitely worth checking out.

00:09:28: In answer to a question from Fabien Beuret I mention that the CAP CodeJam content was temporarily "resting" ... and it's now available online at

00:09:50: Highlighting streamer CodebaseAlpha who covers interesting topics including GraphQL and Alexa skills.

00:10:25: Starting with today's topic, that we started to look at in the previous episode (Ep.15) - building a UI for our little Northbreeze backend service, using annotations and Fiori Elements.

00:12:50: Looking at the project in VS Code to see what we've got so far, including a glimpse at the data model and the CSV files. We note that we're using the managed and cuid aspects to give us some default properties in some of our entity definitions.

00:15:50: Checking the latest version of the CDS Language Support for VS Code extension (available in the Cloud section of the SAP Development Tools site ... it is still at 1.1.1 but I hear that it will be updated before the end of this month.

00:17:10: Checking the latest version of @Sap/cds with npm info @Sap/cds shows that it's still at 3.7.1.

00:17:30: Looking at the Northbreeze service definition (in service.cds) and noting that according to best practice, we should actually omit the extension of referenced files, so they're not language specific. Here that means changing from:
using northbreeze from '../db/model.cds';

using northbreeze from '../db/model';

which subtly allows for those definitions to be available not only in "source" CDS format but perhaps also in the canonical Core Schema Notation (CSN) (pronounced "season") format that we have seen in early episodes when we explored the cds command line tool and the REPL.

00:18:35: Deploying and running the service, and checking that we can see the suppliers in the appropriate entityset (via URL http://localhost:4004/breezy/Suppliers).

00:19:40: Noticing the message:
[cds] - serving static resources from ./app

which implies that it will make available resources that we put there.

00:20:00: So we create the app/ directory with an index.html file in there with a simple "hello". When reloading the root resource at http://localhost:4004 we now get that "hello" resource, rather than the default "Welcome to" page. Nice! The name app/ is also a convention, just like db/ and srv/.

Of course, we can still access the individual services via their normal URLs too. This also gives us a clue as to why the services themselves are not at the root (for example our main service in this project is at /breezy/).

00:22:10: Bringing in some sample content for our new index.html, which looks like this:




<script id="sap-ui-bootstrap"

<body class="sapUiBody" id="content"></body>

This, if you're not familiar, is a typical "bootstrap" page for UI5, and it also includes a script tag to include the SAP Fiori launchpad sandbox, a fully functional Fiori launchpad that you can run locally, which is especially useful for development and testing.

When we load this resource we see a blank page, but note that it's been styled (via the sapUiBody class on the body element), so we can see that something is already happening!

00:26:10: In response to a good question from Fabien, we talk briefly about different app serving constellations - the CAP can serve an entire full stack setup, or just the backend services. Flexibility is key.

00:27:30: We start to flesh out the configuration for the sandbox launchpad, by adding another script tag with some JavaScript assignments to a global property at the window level, which looks like this:

window['sap-ushell-config'] = {
applications: {
'browse-suppliers': {
title: 'Browse Suppliers',
additionalInformation: 'SAPUI5.Component=suppliers',
applicationType : 'URL',
url: '/browse/webapp',

This configuration defines a "Browse Suppliers" tile that will appear on the sandbox launchpad, and I'm following the convention here of putting each individial app in its own directory, which is why the url parameter points to a directory called /browse/.

00:31:40: Now we another bit of JavaScript in a further script tag to run a function when UI5 bootstrapping is complete:

sap.ui.getCore().attachInit(function() {

This just creates the sandbox launchpad and places it in the main body of the browser tab (as content refers to the HTML body element).

The result is that we now have our sandbox Fiori launchpad with a nice new tile with "Browse Suppliers" as the title! Of course, at this point there isn't any app to load, so we'll add the app itself next.

00:35:00: Starting to create the /browse/webapp/ directory structure, with some initial content, so we end up with:
+-- browse/
+-- webapp/
+-- Component.js
+-- manifest.json

00:39:20: Adding the content for our UI5 Component file, we get this:

ac => ac.extend('suppliers.Component', {
metadata: { manifest: 'json' }

This refers to a manifest file which contains pretty much everything the app needs to know about itself, regarding data models, routing, and in fact what is displayed, in terms of views.

So let's look at that now:

"": {
"id": "suppliers",
"title": "Browse Suppliers",
"dataSources": {
"Breezy": {
"uri": "/breezy/",
"settings": {
"odataVersion": "4.0"
"sap.ui5": {
"dependencies": { "libs": { "sap.fe": {} } },
"models": {
"": {
"dataSource": "Breezy",
"settings": { "synchronizationMode": "None" }
"routing": {
"routes": [
"pattern": "",
"name": "SuppliersList",
"target": "SuppliersList"
"targets": {
"SuppliersList": {
"entitySet": "Suppliers",
"viewName": "sap.fe.templates.ListReport"

00:45:45: Note that the data source that we've been creating (in the form of the "Breezy" service) is defined in the "" section of this manifest file.

The rest of the manifest file consists of an "sap.ui5" section, which defines dependencies, models and routing (which is also where the views are defined, in the form of views from the sap.fe.templates library).

00:48:40: We have a quick look at the standard tutorial on Routing in the UI5 SDK, which is the Navigation and Routing tutorial, which you can have a look at if you want to understand more of what's being defined in the "routing" section of the manifest file here.

00:51:35: Now when we select the tile in the sandbox launchpad, we get a sort of app, already half-working. There's no data displayed, but we can see that it is indeed showing a "list report" style UI. Wonderful!

We note that the four filter fields in the UI are there because there are four fields in the entity definition (Suppliers) to which we're referring in the manifest file. As a reminder, here's what the Suppliers entity definition looks like in model.cds:
entity Suppliers {
key ID : Integer;
name : String(40);
country : String(15);
products : Association to many Products on products.supplier = $self;

00:52:45: Tantalisingly close! What we need to do now is add some annotations that will glue everything together (the generic Fiori Elements based view, and the data in the OData service).

So we add a new file index.cds at the same level as index.html, with the following content:
using from '../srv/service';

annotate northbreeze.Suppliers with @(
UI: {
SelectionFields: [],
LineItem: [
{ Value: ID, Label: 'ID' },
{ Value: name, Label: 'Name' },
{ Value: country, Label: 'Country' }
HeaderInfo: {
TypeNamePlural: 'Suppliers'

00:57.25: After adding this, we redeploy (as these are CDS changes) and restart, and check what we get in the UI (we're already on the appropriate hashpath based URL in the launchpad).

After sorting out some browser cacheing issue, we finally see that through the power of annotations and Fiori Elements, we get a wonderfully pretty fully-functional app for very little effort at all. Result! Just in time to end the stream. See you next time!