Technical Articles
Working with Cards on UI5 1.62
If you’ve already navigated through SAP Fiori Design Guidelines you probably have already bumped into the Overview Page concept, a page supposed to be the entry point to a user, having all the information and actions he or she daily needs. Until now, this layout was only available in Fiori Elements, those data-driven generated applications, but now, in UI5 1.62 version, we have the opportunity to develop our own pages using Cards that are the OVP layout basis. Currently, this component has really confusing documentation, so I thought I could share with you what I’ve found and show you how to create a simple application using them.
All code shown here is available in my Github repo.
So, first of all, I created a simple blank UI5 app to start with. Inside our main page, to display Cards, we can use sap.f.CardContainer as an aggregator (this component doesn’t have documentation yet, but is used in some samples). Then, we can define as many Cards as we want, like this:
<mvc:View controllerName="card-blog.Sample.controller.Dashboard"
xmlns:mvc="sap.ui.core.mvc" displayBlock="true"
xmlns="sap.m"
xmlns:f="sap.f"
xmlns:w="sap.ui.integration.widgets"
xmlns:core="sap.ui.core">
<Shell id="shell">
<App id="app">
<pages>
<Page id="page"
title="{i18n>pageTitle}">
<content>
<f:CardContainer>
<w:Card />
</f:CardContainer>
</content>
</Page>
</pages>
</App>
</Shell>
</mvc:View>
Ok, if you try to run this app, you’ll see that the page is still blank. So, let’s take a look a the Card properties:
Height and width are self-explanatory, but this manifest was my main problem when trying to develop cards. Type any doesn’t help too, we have no idea what to put in here. So, there are some samples with examples of how to define a manifest, but I’ll compile here everything that is possible.
First of all, the manifest is simply a JSON file you can define within your files structure. It always starts like this:
"sap.card": {
"type": "List" //or Analytical
...
}
And you define all the properties inside this object. Currently, you can create List or Analytical cards, so I’ll show you which properties you can use in each of them.
List Card
Header
Default
The default header has these options:
{
"ListDefaultHeader": {
"sap.card": {
"type": "List",
"header": {
"title": "Title",
"subTitle": "Subtitle",
"icon": {
"src": "sap-icon://accept",
"alt": "AltIcon",
"shape": "Circle",
"text": "IconText",
"backgroundColor": "green",
"color": "#fff"
},
"status": {
"text": "status"
}
}
}
}
}
It generates this card:
I couldn’t really make backgroundColor and color work, but the options are there, maybe I’m missing something.
Numeric
The numeric header has these options:
"ListNumericHeader": {
"sap.card": {
"type": "List",
"header": {
"title": "Title",
"subTitle": "Subtitle",
"type": "Numeric",
"unitOfMeasurement": "g",
"mainIndicator": {
"number": "100",
"trend": "Down", //Down, None or Up
"state": "Critical" //Critical, Error, Good or Neutral
},
"details": "Details",
"sideIndicators": [
{
"title": "SideIndicator1",
"number": "200",
"unit": "mg"
},
{
"title": "SideIndicator2",
"number": "400",
"unit": "mg"
}
]
}
}
}
And it looks like this:
For the numeric header, we can fetch data, but I’ll talk about this later.
Content
On List cards, we define where the data comes from and how it should be shown for each item in the list. For hardcoded data, you can define it like this:
"content": {
"data": {
"json": [
{
"title": "Item1 Title",
"description": "Item1 Description",
"info": "Item1 Info",
"state": "Error"
},
{
"title": "Item2 Title",
"description": "Item2 Description",
"info": "Item2 Info",
"state": "Warning"
},
{
"title": "Item3 Title",
"description": "Item3 Description",
"info": "Item3 Info",
"state": "Success"
}
]
},
"item": {
"title": {
"label": "TitleLabel",
"value": "{title}"
},
"description": {
"label": "DescLabel",
"value": "{description}"
},
"info": {
"label": "InfoLabel",
"value": "{info}",
"state": "{state}" //Error, Success, Warning or None
},
"highlight": "{state}", //Error, Success, Warning, None or Information
"icon": {
"src": "sap-icon://action",
"alt": "AltIcon",
"shape": "Circle", //Square or Circle
"text": "IconText",
"backgroundColor": "green",
"color": "#fff"
}
}
}
And it looks like this:
Of course, you won’t always use data defined like this. If you have an API endpoint to fetch data from, you can use the request property, instead of json:
"data": {
"request": {
"mode": "cors", //no-cors, same-origin or cors
"method": "GET", //GET or POST
"parameters": {
"type": "1"
},
"headers": {
"x-csrf-token": "123456789"
},
"url": "https://urltest.com/test"
},
"path": "/Items"
}
Inside request, the only required property is url, so only use the other ones if needed.
With this structure, you can already do a lot with lists (visually, at least), but some main features are still missing, like setting an onClick callback for the items.
Analytical Card
Header
Header works exactly the same for both types of cards.
Content
As stated in Fiori Guidelines for Analytical Cards:
The analytical card is used for data visualization. It consists of two areas – a header area (either a standard header or a KPI header) and a chart area with a visual representation of the data.
Its structure is as follow:
"content": {
"data": {
"json": [
{
"Dimension": "Dimension1",
"Measure": 1
},
{
"Dimension": "Dimension2",
"Measure": 2
},
{
"Dimension": "Dimension3",
"Measure": 3
}
]
},
"chartType": "Line", //Line, StackedColumn, StackedBar or Donut
"legend": {
"visible": true,
"position": "Top", //Top, Bottom, Left, Right
"alignment": "Center" //TopLeft, Center
},
"plotArea": {
"dataLabel": {
"visible": true,
"showTotal": true
},
"categoryAxisText": {
"visible": true
},
"valueAxisText": {
"visible": true
}
},
"title": {
"visible": true,
"text": "Chart title",
"alignment": "Left" //Left, Center, Right
},
"measureAxis": "valueAxis",
"dimensionAxis": "categoryAxis",
"dimensions": [
{
"label": "Dimension1",
"value": "{Dimension}"
}
],
"measures": [
{
"label": "Measure1",
"value": "{Measure}"
}
]
}
The result is this chart:
Of course, the data can be fetched from an API as shown before.
So, as of this version, that’s all we can achieve using cards. Personally, this is an exciting addition, and I’m looking forward to the next steps and types of Cards we’ll be able to use in the future. Information on how to set the manifests to the model and for the complete code, head to my Github repo.
Hi Lucas,
that's great news! Although the implementation via manifest is a bit appalling... I guess it makes it hard to create/change cards dynamically.
Can you elaborate on the CardContainer control itself? How to manipulate the layout of the cards? For example can you set how many cards are displayed in one row? Or is it a fixed layout like the Grid? Unfortunately, the CardContainer control is not included in the API reference.
BR, Klaus
Hey, Klaus!
I have to agree with you, the manifest is really weird for me too, as it seems very different from everything else implemented on UI5.
As of the CardContainer, unfortunately, I don't have much more information than you do, but you can control Cards in each row using CardItemLayout, like this:
Each row has 12 columns, so if you set it like this, you get two Cards in the first row and one in the second row extending to the middle, like this:
Hope this helps!
Great, thanks!
I played around a little with your sample - you can really make it look like an overview page 🙂
The way I can imagine a real implementation is by creating the card json in the backend and just putting the string into a JSON model on the frontend. I'll have to try that some day.
BR, Klaus
Hi Lucas,
the
class is no longer available.
After some research, I found the class sap.ui.layout.cssgrid.ResponsiveColumnLayout which I suppose should do the same thing. Have you found a workaround for the time? Any advice would be deeply appreciated.
Regards,
Dimitar.
Hello Dimitar!
I haven’t worked a lot with cards in newer versions of UI5, but I used BlockLayout to organize my screen that had several cards, but I didn’t find any official recommendation on what to use.
Anyway, if you’re still using manifest cards, I suggest you take a look to sap.f.Card as it's much more flexible
BR
Hi Dimitar,
The experimental
sap.f.CardContainer
has been renamed tosap.f.GridContainer
since 1.65 (commit).Some parts of the APIs are still experimental, so not everything might work as expected.
___
API reference:
sap.f.GridContainer
Hello,
is there any way to catch and add a click Event to the Items in the Card.
I Have a Highlight List in my Card and want the single Items to be clickable.
Or can i add a Button or something in the card.
BR, Jonas
Hello, Jonas!
I can say to you that at least inside the manifest definition, there's no way to set a click event yet. Hopefully, it's in the plans for the near future.
What I can't confirm, and I didn't have time to play around yet, is trying to get the control in runtime and doing something like "control.addEventListener("click", callback)". If you test this, please share with us the results.
Yeah i got a Way to solve my Problem, here is how.
First thing, you need to add a Id to your Card in the View.
And here my Example for the Controller
You also can define any other properties from the Standard List Item.
Result look like this, got a Card with a Navigation List Item, in your Controller in the onItemPress Method you can know code what should happen by the Click.
I didn´t try it yet buy maybe you can also bind a path to the cardid and add the List item add Template
Thanks for sharing!
Hello
I want to use OData service for data binding. I have done this way. But its not working. Please help me with this.
Hello, Dhanasupriya!
Are there any error messages on DevTools? I imagine this could be a CORS problem. And, are you using version 1.62 of UI5?
Hi Lucas Heim,
Is there anyway to set the start and end values in Analytical Card Line chart area for Y-axis?
Regard,
Anmol
Hello, Anmol, sorry for the late answer. All the properties available as of UI5 1.62 are in my snippets on the post. This is probably being upgraded for the upcoming versions, maybe I should do a new post already 🙂
Hello Lucas,
I see that you have requested the data using url(service) in the list card. Is there a way we can use the JSON model declared in manifest to pass to the aggregation property in the list card and use those elements. Thank you in advance.
Hello!
In newer versions, instead of "request", you can use "service" and inform the name of your manifest service.
Hello!
Thanks for the reply. I am not sure if you for my question. Let me try to explain in detail.
I have a JSON model declared here in manifest.json
I am setting a new property to the JSON model in controller before loading the card.
that.getOwnerComponent().getModel("viewSet").setProperty("/TeamSet", oData.results);
Now I want to know how to I give the above path in the list card manifest for me to using the aggregated data for display. Please help. Thank you.
Oh, ok, got it now. I would recommend you use sap.f.Card. Since my post, new things were done in UI5, and now the guidelines for using this card I used are the following:
When to use
When not to use
So, you should probably use sap.f.Card (available from 1.64 onwards), here is a sample: https://sapui5.hana.ondemand.com/#/entity/sap.f.Card/sample/sap.f.sample.Card/code
Hello Lucas,
Hope you are doing good!
I am using sap.f.Card to generate a card and there needs to be a scrollable table/list, within the card.
More details for it can be found via the url:
https://answers.sap.com/questions/12873159/scrollable-tablelist-withininside-sapfcard.html
Can you please, provide your views, on the same?
BR,
Sushant
Hello, Sushant!
Sorry I've not been able to play around with sap.f.Card. Have you tried using a Scroll Container?
Hello, I am struggling with Donut Chart. Could you tell me how to switch from relative values(described in %) to absolute values? I can’t find any property in card manifest corresponding for that ;/
Hi Kamil,
could you please let me know whether your were able to display the obsolute values instead of the relative values in cards ?
Regards,
Omkar
Hi,
I cant able to navigate to the other URL, in action list please help me with this, here is my code
Model:
view:
Hello!
Is there any way to connect to an already existing destination in SAP Cloud Platform? I followed this: https://openui5nightly.hana.ondemand.com/test-resources/sap/ui/integration/demokit/cardExplorer/webapp/index.html#/learn/features/destinations
And apparently a destination must be created in the controller. However, I'm connecting my card to a SAP system backend and I must define a basic authentication (user and password). I'm getting the following error:
The destination was properly set in the controller and it's trying to make a request to the backend system, but the connection just failed because of the authentication.
Any ideas on how can it be solved?
Hello Juan!
Have you tried using sap.f.Card? From the guidelines, when to not use the Card I've described in this post:
When to use
When not to use
In your case, I believe you'd declare your destination in neo-app.json and the manifest for your app and then you'd have an application model which would then be bound to your card. For this, use sap.f.Card.
Hi Lucas,
Great Blog!!
Is it possible to add custom CSS in UI Cards? I have tried adding a CSS file path to the manifest file.
But it didn't work. Can you please help?
Regards,
Saurabh
Hi Saurabh!
From the documentation, it seems like you can use Control inherited methods as "addStyleClass" to add CSS as you'd do for other UI5 controls.