RAP from scratch · Lesson 5 of 6
A traffic light in Fiori with RAP: color-code your books' ratings
Color each book's rating red, yellow or green with a calculated field in the CDS view and one annotation, then add stars to the detail page. No JavaScript.
The book list from lesson 3 shows the rating as a number: 4, 5, 3. It works, but you have to read it. A traffic light turns it into something you grasp at a glance:
| Rating | Color | Meaning |
|---|---|---|
| 0 | gray | Not rated |
| 1–2 | red | Poor |
| 3 | yellow | Average |
| 4–5 | green | Good |
The best part: in RAP the traffic light is not programmed. There is no JavaScript or UI5, and you don’t even need an ABAP class. It takes three small changes, one per layer:
ZR_LibBook (1) calculates the color: a new field with CASE
ZC_LibBook (2) lets it through to the service
MDE (3) tells Fiori which field to paint with that color
At the end, as a bonus, we will show the rating as stars in the header of the detail page.
Before you start: you need the library from lessons 2, 3 and 4. Lesson 4 is needed to change the rating from the app while testing.
Guide code: the code follows ABAP Cloud syntax, but it was not compiled on an SAP system for this tutorial. If something does not activate on your system, the ADT message points to the exact line.
How Fiori understands colors
Fiori Elements knows nothing about books or ratings. It only understands a criticality number:
| Value | Color | Name in Fiori |
|---|---|---|
0 |
gray | Neutral |
1 |
red | Negative |
2 |
yellow | Critical |
3 |
green | Positive |
So the job comes down to two things: calculate that number for each book, and tell Fiori which field to apply it to.
1. Calculate the criticality in the Root View Entity
Open ZR_LibBook and add a calculated field right after Rating. It doesn’t exist in the table: the database calculates it on read, with a CASE.
Excerpt from ZR_LibBook (lesson 2). It goes between rating as Rating, and @Semantics.amount.currencyCode: 'CurrencyCode'; the rest of the view stays the same:
rating as Rating,
case
when rating = 0 then 0 -- not rated: gray
when rating <= 2 then 1 -- 1 or 2: red
when rating = 3 then 2 -- 3: yellow
else 3 -- 4 or 5: green
end as RatingCriticality,
Two details:
- The order of the
whenclauses matters. They are evaluated top to bottom and the first match wins. That is whyrating = 0comes first: otherwise0would fall intorating <= 2and come out red. - Inside the
CASEyou userating, the table’s name, notRating, the view’s alias.
Activate ZR_LibBook (Ctrl+F3) and check it with F8 (Data Preview): a RatingCriticality column appears with a 3 or a 2 for each book.
2. Let it through in the projection
A field that is not in the projection doesn’t travel over OData. If you don’t add it, the annotation in step 3 activates without errors, but the traffic light doesn’t show up. It is the most common mistake.
Complete ZC_LibBook (the one from lesson 3, with the new RatingCriticality line):
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
@EndUserText.label: 'Library: books (app)'
@Search.searchable: true
define root view entity ZC_LibBook
provider contract transactional_query
as projection on ZR_LibBook
{
key BookUuid,
@Search.defaultSearchElement: true
BookId,
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
Title,
AuthorId,
_Author.Name as AuthorName,
Pages,
Isbn,
Rating,
RatingCriticality,
Price,
CurrencyCode,
LocalLastChangedAt
}
Activate ZC_LibBook.
3. Paint the field in the Metadata Extension
Now we tell Fiori: “paint the Rating column with the color that RatingCriticality says”. You do it with criticality inside lineItem (the list) and identification (the detail page).
Excerpt from the Metadata Extension of ZC_LibBook (lesson 3). Replace the Rating block with this one and add the RatingCriticality block below it:
@UI: { lineItem: [ { position: 60,
criticality: 'RatingCriticality',
criticalityRepresentation: #WITH_ICON } ],
identification: [ { position: 60,
criticality: 'RatingCriticality' } ] }
Rating;
@UI.hidden: true
RatingCriticality;
criticality: 'RatingCriticality'is the name of the field that carries the color, in quotes.criticalityRepresentation: #WITH_ICONadds an icon (✓, ⚠, ✕) next to the number. That way the traffic light also works for people who can’t tell the colors apart. If you prefer color only, use#WITHOUT_ICON.@UI.hidden: truehidesRatingCriticality: it is a3or a1that only exists to paint, and it means nothing to the user.
Activate the Metadata Extension.
4. Try it
- Open the Service Binding
ZUI_LIB_BOOK_O4, select Book and click Preview. - Click Go. The Rating column is now in color: Mountain Rivers (5), Birds of the South (4) and Winter Tales (4) in green, and The Last Train (3) in yellow.
- What about red? Open The Last Train, click Edit, change the rating to 1 and save. Go back to the list: now it is red.
- Try 0: it shows up gray, not rated.
If the preview was already open, reload it: Fiori caches the service metadata.
Bonus: stars in the detail page header
A colored number works well in the list. On a book’s detail page, stars look better, like in an online store. Fiori has them built in with a Data Point of type #RATING.
You need two things in the same Metadata Extension:
- A Data Point on
Rating, which says how to draw it (stars, out of 5). - A header facet (
purpose: #HEADER) that places it at the top of the detail page.
A facet is a section of the detail page. The one from lesson 3 (id: 'Book') is the body; this new one goes in the header. The facet’s targetQualifier and the Data Point’s qualifier must match: that is what links them.
This is the complete Metadata Extension, with this tutorial’s changes (step 3 and the stars):
@Metadata.layer: #CUSTOMER
@UI.headerInfo: {
typeName: 'Book',
typeNamePlural: 'Books',
title: { type: #STANDARD, value: 'Title' },
description: { value: 'AuthorName' }
}
annotate entity ZC_LibBook with
{
@UI.facet: [ {
id: 'HeaderRating',
purpose: #HEADER,
type: #DATAPOINT_REFERENCE,
targetQualifier: 'Rating',
position: 10
}, {
id: 'Book',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Book',
position: 10
} ]
@UI.hidden: true
BookUuid;
@UI: { lineItem: [ { position: 10 } ], identification: [ { position: 10 } ], selectionField: [ { position: 10 } ] }
BookId;
@UI: { lineItem: [ { position: 20 } ], identification: [ { position: 20 } ] }
Title;
@UI: { lineItem: [ { position: 30 } ], identification: [ { position: 30 } ], selectionField: [ { position: 20 } ] }
AuthorId;
@UI: { lineItem: [ { position: 40 } ], identification: [ { position: 40 } ] }
AuthorName;
@UI: { lineItem: [ { position: 50 } ], identification: [ { position: 50 } ] }
Pages;
@UI: { lineItem: [ { position: 60,
criticality: 'RatingCriticality',
criticalityRepresentation: #WITH_ICON } ],
identification: [ { position: 60,
criticality: 'RatingCriticality' } ],
dataPoint: { qualifier: 'Rating',
title: 'Rating',
visualization: #RATING,
targetValue: 5 } }
Rating;
@UI.hidden: true
RatingCriticality;
@UI: { lineItem: [ { position: 70 } ], identification: [ { position: 70 } ] }
Price;
@UI.hidden: true
LocalLastChangedAt;
}
Activate and reload the preview. Open a book: at the top, next to the title, its stars appear. Mountain Rivers has all five filled in.
If something doesn’t show up
| Symptom | Usual cause |
|---|---|
| The column has no color | RatingCriticality is not in the ZC_LibBook projection (step 2) |
| Everything is gray | The CASE always returns 0: check that it compares rating and the order of the when clauses |
0 comes out red |
when rating = 0 is not the first clause of the CASE |
| A column with numbers 1, 2, 3 appears | @UI.hidden: true is missing on RatingCriticality |
| No stars | The facet’s targetQualifier doesn’t match the Data Point’s qualifier ('Rating' in both) |
| Nothing changes | The preview still has the old metadata: reload it |
Summary
- Fiori paints colors from a criticality number: 0 gray, 1 red, 2 yellow and 3 green.
- That number is calculated in the CDS view with a
CASE, with no ABAP or JavaScript, and projected so it reaches the service. - In the Metadata Extension,
criticalitylinks the visible field to its color, and@UI.hiddenhides the helper field. - A
#RATINGData Point in a header facet turns the rating into stars.
The same pattern works for any status: open or closed orders, low stock, overdue dates. Change the CASE and everything else stays the same.
Get new tutorials by email
One email when something new is published. No spam; unsubscribe anytime.
I will email you to confirm your subscription. Data handled under the privacy policy.