Skip to Content
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.

15 Comments
You must be Logged on to comment or reply to a post.
  • 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:

      <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!

      • 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

  • 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.

    <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

    • 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?

    • 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 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