SuperAPI AI Directory

fiori-annotations

Data & analytics

View repository

Updated 10-16 02:37

About this skill

Fiori Annotations — Best Practices

Primary reference: https://cap.cloud.sap/docs/guides/uis/fiori OData annotation vocabulary: https://ui5.sap.com/#/topic/030faebe70b34198b17a93b4c6e7b4d7 Feature showcase: https://github.com/SAP-samples/fiori-elements-feature-showcase

Always annotate in app/<app-name>/annotations.cds — never inline in entity definitions, never in webapp/annotations.xml in CAP projects.


Essential annotation structure for List Report + Object Page

using OrderService from '../../srv/order-service';

annotate OrderService.Orders with @(

// ── List Report ──────────────────────────────────────────────── UI.HeaderInfo: { TypeName: 'Order', TypeNamePlural: 'Orders', Title: { Value: orderNumber }, Description: { Value: customer.name } },

// Columns in the list table UI.LineItem: [ { Value: orderNumber, Label: 'Order #' }, { Value: customer.name, Label: 'Customer' }, { Value: orderDate }, { Value: totalAmount }, { Value: currency_code }, { Value: status, Criticality: statusCriticality }, // Inline action button { $Type: 'UI.DataFieldForAction', Action: 'OrderService.submitOrder', Label: 'Submit' } ],

// Filter fields above the table UI.SelectionFields: [ status, customer_ID, orderDate ],

// ── Object Page ──────────────────────────────────────────────── UI.Facets: [ { $Type: 'UI.ReferenceFacet', Label: 'General', ID: 'GeneralFacet', Target: '@UI.FieldGroup#General' }, { $Type: 'UI.ReferenceFacet', Label: 'Items', ID: 'ItemsFacet', Target: 'items/@UI.LineItem' // child entity table } ],

UI.FieldGroup #General: { $Type: 'UI.FieldGroupType', Data: [ { Value: orderNumber }, { Value: orderDate }, { Value: totalAmount }, { Value: status } ] } );


---

## Criticality — traffic light colours

```cds
// In your service entity or as calculated element:
entity Orders {
  status            : String enum { Draft; Open; Approved; Rejected; };
  statusCriticality : Integer;  // 0=None 1=Red 2=Yellow 3=Green 5=Purple
}

// In the handler — set criticality based on status:
this.after('READ', Orders, orders => {
  for (const o of orders) {
    o.statusCriticality = 
      o.status === 'Approved' ? 3 :   // green
      o.status === 'Rejected' ? 1 :   // red
      o.status === 'Open'     ? 2 : 0 // yellow / none
  }
})

// In annotations — reference the criticality field:
{ Value: status, Criticality: statusCriticality }

Value Help (ValueList)

// Simple value help from an associated entity
annotate OrderService.Orders:customer_ID with @(
  Common.ValueList: {
    CollectionPath: 'Customers',
    Parameters: [
      { $Type: 'Common.ValueListParameterOut',
        LocalDataProperty: customer_ID,
        ValueListProperty: 'ID' },
      { $Type: 'Common.ValueListParameterDisplayOnly',
        ValueListProperty: 'name' }
    ]
  },
  Common.ValueListWithFixedValues: false
);

Common.Text — show description next to ID

// Show customer name next to customer ID in all UI contexts
annotate OrderService.Orders:customer_ID with
  @Common.Text: customer.name
  @Common.TextArrangement: #TextFirst;  // "ACME Corp (C001)"

Field labels via @title

// Set once on the entity — applies everywhere in the UI
annotate OrderService.Orders with {
  orderNumber  @title: 'Order Number';
  orderDate    @title: 'Order Date';
  totalAmount  @title: 'Total Amount';
  status       @title: 'Status';
}

Hiding fields

// Always hidden
annotate OrderService.Orders:technicalField with @UI.Hidden;

// Conditionally hidden (expression)
annotate OrderService.Orders:internalNote with @UI.Hidden: (status != 'Admin');

Multi-line text

annotate OrderService.Orders:description with @UI.MultiLineText;

Header Facets on Object Page

UI.HeaderFacets: [
  {
    $Type:  'UI.ReferenceFacet',
    Target: '@UI.DataPoint#Amount'
  },
  {
    $Type:  'UI.ReferenceFacet',
    Target: '@UI.DataPoint#Status'
  }
],

UI.DataPoint #Amount: {
  Value: totalAmount,
  Title: 'Total Amount'
},

UI.DataPoint #Status: {
  Value:       status,
  Criticality: statusCriticality,
  Title:       'Status'
}

Actions — bound vs unbound

// Bound action (acts on selected record)
{ $Type: 'UI.DataFieldForAction',
  Action: 'OrderService.submitOrder',
  Label:  'Submit',
  Determining: true }  // shows in footer of Object Page

// Unbound action (global, in table toolbar)
{ $Type: 'UI.DataFieldForAction',
  Action: 'OrderService.EntityContainer/createDraftOrder',
  Label:  'New Draft' }

Annotation file organisation

For large apps, split annotations by concern:

app/orders/
├── field-annotations.cds     ← @title, @UI.Hidden, Common.Text
├── list-report.cds            ← UI.LineItem, UI.SelectionFields
├── object-page.cds            ← UI.Facets, UI.FieldGroup, UI.HeaderFacets
└── value-helps.cds            ← Common.ValueList

Import all in a single index.cds:

using from './field-annotations';
using from './list-report';
using from './object-page';
using from './value-helps';

Common mistakes to avoid

  • ❌ Putting annotations in webapp/annotations.xml — not compiled by CAP, silently ignored

  • ✅ Always use app/<name>/annotations.cds

  • ❌ Hardcoded label strings in UI.LineItem — not translatable

  • ✅ Use @title on the field + '{i18n>key}' for labels

  • ❌ Using statusCriticality as a plain Integer without @UI.Hidden — shows as a column

  • ✅ Always hide technical helper fields: @UI.Hidden

  • ❌ Referencing a child entity table without @UI.LineItem on the child entity

  • ✅ Child entity needs its own UI.LineItem annotation for the table facet to render

  • ❌ Forgetting ID on facets when using UI.CollectionFacet — breaks rendering

  • ✅ Every CollectionFacet must have a unique ID

  • ❌ Mixing OData V2 annotation syntax (@sap.label) with V4 vocabulary

  • ✅ V4 only: @title, @Common.Text, @UI.*