By the end of this chapter, we will have added a remote bookshop data source to our app and stored the data in a model. We will also have added a table displaying this model data.
1. Add @sap/ux-ui5-tooling
as a dependency in the package.json
2. Install dependencies
3. Configure the fiori-tools-proxy
in the ui5.yaml
4. Add a new dataSource
and model
to the webapp/manifest.json
5. Add a new <Table />
to the webapp/view/App.view.xml
6. Inspect the app in the browser
We want to consume a remote data source for our bookshop. Unfortunately, we cannot call the remote source directly from our UI5 app, as this would lead to CORS issues. We need a middleware that handles the API call for us on the server side. For that, we need to add another Node.js based package as a dependency and install it later on.
➡️ Replace the current content of the package.json
file with the following code:
{
"name": "bookshop",
"version": "0.0.1",
"scripts": {
"dev": "ui5 serve --open \"index.html\""
},
"devDependencies": {
"@ui5/cli": "^4",
"@sap/ux-ui5-tooling": "^1"
}
}
We added the @sap/ux-ui5-tooling package as a development dependency and also added it to the ui5.dependencies
section, which will make sure the UI5 Tooling finds it. This package is part of the SAP Fiori Tools and seamlessly integrates with the UI5 Tooling. It contains a selection of custom middlewares that can be used for UI5 development.
In order to use the newly added dependency, we have to install it.
➡️ Run the following command in the bookshop/
directory:
npm install
We successfully installed all our dependencies.
We can now configure the custom middleware in our ui5.yaml
.
➡️ Replace the current content of the ui5.yaml
with the following code:
specVersion: '2.6'
metadata:
name: bookshop
type: application
server:
customMiddleware:
- name: fiori-tools-proxy
afterMiddleware: compression
configuration:
backend:
- path: /v2/browse
url: https://developer-advocates-free-tier-central-hana-cloud-instan3b540fd6.cfapps.us10.hana.ondemand.com
We configured a custom middleware using the fiori-tools-proxy
. This middleware will handle all calls that our UI5 app initiates to the v2/browse/
path and will proxy (think "forward") them to https://developer-advocates-free-tier-central-hana-cloud-instan3b540fd6.cfapps.us10.hana.ondemand.com
. We can now add the v2/browse/
path as the data source to our UI5 application.
Models are a major part of UI5 development. We use models to store data in our app ("data layer"). Models are not bound to or represented by a specific file, but are dynamic objects that can be consumed and modified by different parts of the app. They can be created via the manifest.json
file or via a controller.
➡️ Replace the current content of the webapp/manifest.json
with the following code:
{
"sap.app": {
"id": "codejam",
"type": "application",
"title": "CodeJam Bookshop",
"applicationVersion": {
"version": "1.0.0"
},
"dataSources": {
"remoteBookshop": {
"uri": "/v2/browse/",
"type": "OData",
"settings": {
"odataVersion": "2.0"
}
}
}
},
"sap.ui5": {
"rootView": {
"viewName": "sap.codejam.view.App",
"type": "XML",
"id": "app"
},
"models": {
"": {
"dataSource": "remoteBookshop"
}
}
}
}
We defined a new model with an empty string as its name, which makes it the default model of the app. The dataSource
for the model is the remoteBookshop
, which is a new dataSource
we created that calls the /v2/browse/
path and therefore gets proxied by the middleware (see step 2 of this chapter). The model we created is of type OData V2, which is a RESTful protocol that heavily used within the SAP ecosphere. We will learn more about OData and its strengths in the upcoming chapters.
We can now go ahead an consume the newly created model in our webapp/view/App.view.xml
.
➡️ Paste the following code into the <content />
section of the <Panel />
in our existing view:
<Table
items="{ path: '/Books', parameters: { expand: 'genre' } }">
<columns>
<Column>
<Text text="Book" />
</Column>
<Column>
<Text text="Author" />
</Column>
<Column>
<Text text="Genre" />
</Column>
<Column>
<Text text="Price" />
</Column>
<Column>
<Text text="Stock" />
</Column>
</columns>
<items>
<ColumnListItem
vAlign="Middle"
type="Active">
<cells>
<ObjectIdentifier
title="{title}"/>
<Text
text="{author}" />
<Text
text="{genre/name}" />
<ObjectNumber
number="{price}"
unit="{currency_code}" />
<Text
text="{stock}" />
</cells>
</ColumnListItem>
</items>
</Table>
We created a Table that displays the books from our bookshop data. Let's go through the code step by step to better understand how we did it:
- We created a new
<Table />
that holds<columns />
and<items />
(think "rows") as its aggregations. - The
<Table />
has anitems
attribute that we want to bind to theBooks
in our data model (you can access the data at https://developer-advocates-free-tier-central-hana-cloud-instan3b540fd6.cfapps.us10.hana.ondemand.com). For that we make use of a concept called data binding (more specifically list binding). Data binding is very important in UI5 and requires a special syntax. We use curly brackets ({}
) and specify thepath
to the data in the model we want to bind. This list binding automatically creates child controls (<items />
) according to model data (like cloning a template). Additionally, we specify theexpand
parameter that will be sent with the OData request when getting the data. This is not always necessary, but rather specific to our data model as thegenre
information is nested and not expanded by default. - The
<columns />
aggregation inside the<Table />
holds several<Column />
controls that each hold a<Text />
control. These are the texts in the header row of our<Table />
. - The
<items />
(rows) of our<Table />
hold a<ColumnListItem />
, which serves as a wrapper for the<cells />
of each row. The controls inside the<cells />
aggregation have to match our<columns />
with respect to the order of the content (book, author, genre, price, stock). - Check the documentation to see what the
vAlign
andtype
attributes for the<ColumnListItem />
do. - Inside the
<cells />
we display the actual data and make use of the data binding concept again. This time it's a relative property binding (relative to the parent's list binding), which is indicated by omitting the slash ('slash'). The whole<Table />
is bound toBooks
, so we can bind the controls inside the<cells />
aggregation to individual book properties, such a the title and author. - For the controls inside the
<cells />
aggregation we chose controls that suit the type of data they display.
Check the documentation to learn more about data binding and its different types.
This is what our view now looks like (<Table />
collapsed in the screen shot):
➡️ Move over to the browser and refresh the page to see the table:
Continue to - Chapter 04 - Creating and Extending the First Controller