Skip to Content
Technical Articles
Author's profile photo Lucas Heim

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.

Assigned Tags

      27 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Klaus Kronawetter
      Klaus Kronawetter

      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

      Author's profile photo Lucas Heim
      Lucas Heim
      Blog Post Author

      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:

      <f:CardContainer>
        <w:Card height="23rem" manifest="{manifests>/ListDefaultHeader}">
          <w:layoutData>
              <f:CardItemLayoutData columns="6" />
          </w:layoutData>
        </w:Card>
      
        <w:Card height="23rem" manifest="{manifests>/ListNumericHeader}">
        <w:layoutData>
              <f:CardItemLayoutData columns="6" />
          </w:layoutData>
        </w:Card>
      
        <w:Card height="23rem" manifest="{manifests>/AnalyticalCard}">
        <w:layoutData>
              <f:CardItemLayoutData columns="6" />
          </w:layoutData>
        </w:Card>
      </f:CardContainer>

      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!

      Author's profile photo Klaus Kronawetter
      Klaus Kronawetter

      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

      Author's profile photo Dimitar Fenerski
      Dimitar Fenerski

      Hi Lucas,

      the

      f:CardContainer

      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.

      Author's profile photo Lucas Heim
      Lucas Heim
      Blog Post Author

      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

      Author's profile photo Boghyon Hoffmann
      Boghyon Hoffmann

      Hi Dimitar,

      The experimental sap.f.CardContainer has been renamed to sap.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

      Author's profile photo Jonas Alin
      Jonas Alin

      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

      Author's profile photo Lucas Heim
      Lucas Heim
      Blog Post Author

      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.

      Author's profile photo Jonas Alin
      Jonas Alin

      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.

      <w:Card height="auto" manifest="{manifests>/yourname}" id="cardid">
         <w:layoutData>
            <f:CardItemLayoutData columns="4" />
         </w:layoutData>
      </w:Card>

       

      And here my Example for the Controller

      var oItem = new sap.m.StandardListItem({
         title: "your Title",
         description: "Description ",
         type: sap.m.ListType.Navigation,
         press: this.onItemPress,
         highlight: "Success"
      });
      this.byId("cardid").getCardContent()._getList().addItem(oItem);

      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

      Author's profile photo Lucas Heim
      Lucas Heim
      Blog Post Author

      Thanks for sharing!

      Author's profile photo Dhanasupriya Sidagam
      Dhanasupriya Sidagam

      Hello

      I want to use OData service for data binding. I have done this way. But its not working. Please help me with this.

      Author's profile photo Lucas Heim
      Lucas Heim
      Blog Post Author

      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?

      Author's profile photo Anmol Chadha
      Anmol Chadha

      Hi Lucas Heim,

      Is there anyway to set the start and end values in Analytical Card Line chart area for Y-axis?

       

      Regard,

      Anmol

      Author's profile photo Lucas Heim
      Lucas Heim
      Blog Post Author

      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 🙂

      Author's profile photo Srinath Velagala
      Srinath Velagala

      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.

      Author's profile photo Lucas Heim
      Lucas Heim
      Blog Post Author

      Hello!

      In newer versions, instead of "request", you can use "service" and inform the name of your manifest service.

      Author's profile photo Srinath Velagala
      Srinath Velagala

      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.

      Author's profile photo Lucas Heim
      Lucas Heim
      Blog Post Author

      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 you want to reuse the card across apps.
      • When you need easy integration and configuration.

      When not to use

      • When you need more header and content flexibility.
      • When you have to achieve simple card visualization. For such cases, use: Card.
      • When you have to use an application model. For such cases, use: Card.
      • When you need complex behavior. For such cases, use: Card.

       

      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

       

      Author's profile photo Sushant Nath
      Sushant Nath

      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

      Author's profile photo Lucas Heim
      Lucas Heim
      Blog Post Author

      Hello, Sushant!

      Sorry I've not been able to play around with sap.f.Card. Have you tried using a Scroll Container?

      Author's profile photo Kamil Czaplewski
      Kamil Czaplewski

      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 ;/

      Author's profile photo Omkar G
      Omkar G

      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

      Author's profile photo Sam Hilton
      Sam Hilton

      Hi,

      I cant able to navigate to the other URL, in action list please help me with this, here is my code

      Model:

       

      view:

      Author's profile photo Juan Diego Camacho
      Juan Diego Camacho

      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?

      Author's profile photo Lucas Heim
      Lucas Heim
      Blog Post Author

      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 you want to reuse the card across apps.
      • When you need easy integration and configuration.

      When not to use

      • When you need more header and content flexibility.
      • When you have to achieve simple card visualization. For such cases, use: Card.
      • When you have to use an application model. For such cases, use: Card.
      • When you need complex behavior. For such cases, use: Card.

      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.

       

      Author's profile photo Saurabh Parikh
      Saurabh Parikh

      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

      Author's profile photo Lucas Heim
      Lucas Heim
      Blog Post Author

      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.