← Back to tutorials

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.

También disponible en español →

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 when clauses matters. They are evaluated top to bottom and the first match wins. That is why rating = 0 comes first: otherwise 0 would fall into rating <= 2 and come out red.
  • Inside the CASE you use rating, the table’s name, not Rating, 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_ICON adds 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: true hides RatingCriticality: it is a 3 or a 1 that only exists to paint, and it means nothing to the user.

Activate the Metadata Extension.

4. Try it

  1. Open the Service Binding ZUI_LIB_BOOK_O4, select Book and click Preview.
  2. 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.
  3. 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.
  4. 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:

  1. A Data Point on Rating, which says how to draw it (stars, out of 5).
  2. 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, criticality links the visible field to its color, and @UI.hidden hides the helper field.
  • A #RATING Data 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.