RAP Value Helps: Annotation-Based Value Helps in ABAP Cloud

Category
RAP
Published
Author
Johannes

Value Helps are a central element of every Fiori application. They enable users to conveniently select values from predefined lists. In RAP, Value Helps are defined declaratively via CDS annotations - without a single line of UI code.

Basic Concept of Value Helps

Value Helps in RAP are based on the @Consumption.valueHelpDefinition annotation. This links a field with a CDS entity that serves as the value list.

Simple Value Help

The minimal setup consists of the annotation on the target field:

define view entity ZC_SalesOrder
as projection on ZI_SalesOrder
{
@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_Customer',
element: 'CustomerId'
}
}]
key SalesOrderId,
CustomerId,
CustomerName,
OrderDate
}

This configuration automatically displays a value help with all customers from ZI_Customer when the user clicks the CustomerId field.

Structure of the Annotation

@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_ValueHelpEntity', -- Name of the CDS entity
element: 'KeyField' -- Key field (optional)
},
qualifier: 'MyValueHelp', -- Unique identifier
label: 'Customer Selection', -- Dialog title
useForValidation: true, -- Enable validation
additionalBinding: [{...}], -- Additional field mappings
distinctValues: true -- Unique values only
}]

Value Help Entity Design

The entity serving as a Value Help should be specifically optimized for this purpose:

@EndUserText.label: 'Customer Value Help'
@ObjectModel.resultSet.sizeCategory: #XS
@Search.searchable: true
define view entity ZI_CustomerVH
as select from zcustomer
{
@UI.hidden: true
key customer_id as CustomerId,
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
customer_name as CustomerName,
@Search.defaultSearchElement: true
city as City,
country as Country,
@UI.hidden: true
blocked as IsBlocked
}
where blocked = ''

Best Practices for Value Help Entities

AspectRecommendation
Size@ObjectModel.resultSet.sizeCategory: #XS for small lists
Search@Search.searchable for typeahead
FilterWHERE clause for invalid entries
FieldsOnly expose relevant fields

Difference: Simple vs. Complex Value Helps

Simple Value Help

Shows only the key field and optionally a description text:

@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_StatusVH',
element: 'StatusCode'
}
}]
Status,

The Value Help Entity:

define view entity ZI_StatusVH
as select from zstatus
{
key status_code as StatusCode,
status_text as StatusText
}

Complex Value Help

Contains multiple columns, filters, and additional return fields:

@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_MaterialVH',
element: 'MaterialNumber'
},
additionalBinding: [{
element: 'MaterialDescription',
localElement: 'MaterialText',
usage: #RESULT
}, {
element: 'MaterialGroup',
localElement: 'MaterialGroup',
usage: #RESULT
}, {
element: 'BaseUnit',
localElement: 'Unit',
usage: #RESULT
}]
}]
MaterialNumber,
MaterialText,
MaterialGroup,
Unit,

Value Help with Filter Conditions

Filters restrict the displayed values. There are two types: static and dynamic filters.

Static Filter

Filters the Value Help to fixed values:

@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_ProductVH',
element: 'ProductId'
},
additionalBinding: [{
element: 'ProductType',
localConstant: 'FINISHED',
usage: #FILTER
}]
}]
ProductId,

This Value Help shows only products with ProductType = 'FINISHED'.

Dynamic Filter (dependent on other fields)

The filter is based on the value of another field:

define view entity ZC_PurchaseOrder
as projection on ZI_PurchaseOrder
{
key PurchaseOrderId,
@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_VendorVH',
element: 'VendorId'
},
additionalBinding: [{
element: 'PurchasingOrg',
localElement: 'PurchasingOrg',
usage: #FILTER
}]
}]
VendorId,
VendorName,
@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_PurchOrgVH',
element: 'PurchasingOrg'
}
}]
PurchasingOrg
}

Here, only vendors belonging to the selected purchasing organization are displayed.

Combining Multiple Filters

@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_PlantVH',
element: 'Plant'
},
additionalBinding: [{
element: 'CompanyCode',
localElement: 'CompanyCode',
usage: #FILTER
}, {
element: 'SalesOrg',
localElement: 'SalesOrg',
usage: #FILTER
}, {
element: 'IsActive',
localConstant: 'X',
usage: #FILTER
}]
}]
Plant,

Cascading Value Helps (Dependent Value Helps)

Cascading Value Helps are interdependent - the selection in one Value Help affects the options in another.

Example: Country → Region → City

define view entity ZC_Address
as projection on ZI_Address
{
key AddressId,
-- Level 1: Country
@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_CountryVH',
element: 'CountryCode'
},
additionalBinding: [{
element: 'CountryName',
localElement: 'CountryName',
usage: #RESULT
}]
}]
CountryCode,
CountryName,
-- Level 2: Region (filtered by country)
@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_RegionVH',
element: 'RegionCode'
},
additionalBinding: [{
element: 'CountryCode',
localElement: 'CountryCode',
usage: #FILTER
}, {
element: 'RegionName',
localElement: 'RegionName',
usage: #RESULT
}]
}]
RegionCode,
RegionName,
-- Level 3: City (filtered by region)
@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_CityVH',
element: 'CityCode'
},
additionalBinding: [{
element: 'RegionCode',
localElement: 'RegionCode',
usage: #FILTER
}, {
element: 'CityName',
localElement: 'CityName',
usage: #RESULT
}]
}]
CityCode,
CityName
}

Value Help Entities for Cascading

-- Countries
define view entity ZI_CountryVH
as select from zcountry
{
key country_code as CountryCode,
country_name as CountryName
}
-- Regions (with foreign key to country)
define view entity ZI_RegionVH
as select from zregion
{
key region_code as RegionCode,
region_name as RegionName,
country_code as CountryCode -- Filter criterion
}
-- Cities (with foreign key to region)
define view entity ZI_CityVH
as select from zcity
{
key city_code as CityCode,
city_name as CityName,
region_code as RegionCode -- Filter criterion
}

Value Help with Additional Output Fields

Additional output fields automatically transfer values from the Value Help to other fields in the entity.

Example: Material Master Data

define view entity ZC_SalesOrderItem
as projection on ZI_SalesOrderItem
{
key SalesOrderId,
key ItemNumber,
@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_MaterialVH',
element: 'MaterialNumber'
},
additionalBinding: [
-- Return fields
{ element: 'MaterialDescription', localElement: 'MaterialText', usage: #RESULT },
{ element: 'BaseUnit', localElement: 'Unit', usage: #RESULT },
{ element: 'MaterialGroup', localElement: 'MatGroup', usage: #RESULT },
{ element: 'GrossWeight', localElement: 'Weight', usage: #RESULT },
-- Also as filter
{ element: 'SalesOrg', localElement: 'SalesOrg', usage: #FILTER_AND_RESULT }
]
}]
MaterialNumber,
MaterialText,
Unit,
MatGroup,
Weight,
SalesOrg,
Quantity,
NetPrice
}

Usage Options

ValueDescription
#RESULTValue is returned
#FILTERValue serves as filter
#FILTER_AND_RESULTBoth combined

Practical Example: Customer with Address

@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_CustomerVH',
element: 'CustomerId'
},
additionalBinding: [{
element: 'CustomerName',
localElement: 'CustomerName',
usage: #RESULT
}, {
element: 'Street',
localElement: 'CustomerStreet',
usage: #RESULT
}, {
element: 'City',
localElement: 'CustomerCity',
usage: #RESULT
}, {
element: 'PostalCode',
localElement: 'CustomerPostalCode',
usage: #RESULT
}, {
element: 'Country',
localElement: 'CustomerCountry',
usage: #RESULT
}, {
element: 'PaymentTerms',
localElement: 'PaymentTerms',
usage: #RESULT
}]
}]
CustomerId,
CustomerName,
CustomerStreet,
CustomerCity,
CustomerPostalCode,
CustomerCountry,
PaymentTerms,

Multiple Value Helps for One Field

A field can have multiple alternative Value Helps:

@Consumption.valueHelpDefinition: [
{
entity: { name: 'ZI_CustomerVH', element: 'CustomerId' },
qualifier: 'AllCustomers',
label: 'All Customers'
},
{
entity: { name: 'ZI_KeyAccountVH', element: 'CustomerId' },
qualifier: 'KeyAccounts',
label: 'Key Accounts',
additionalBinding: [{
element: 'IsKeyAccount',
localConstant: 'X',
usage: #FILTER
}]
},
{
entity: { name: 'ZI_RecentCustomerVH', element: 'CustomerId' },
qualifier: 'RecentCustomers',
label: 'Recently Used'
}
]
CustomerId,

The user can choose between the Value Helps.

Validation with Value Helps

The annotation useForValidation validates entered values against the Value Help:

@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_CurrencyVH',
element: 'CurrencyCode'
},
useForValidation: true
}]
Currency,

For invalid entries, Fiori automatically displays an error message.

Validation in the Behavior Definition

In addition to UI validation, backend validation should also be implemented:

validation validateCurrency on save { field Currency; }
METHOD validateCurrency.
READ ENTITIES OF zi_salesorder IN LOCAL MODE
ENTITY SalesOrder
FIELDS ( Currency )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
SELECT currency_code FROM zcurrency
INTO TABLE @DATA(lt_valid_currencies).
LOOP AT lt_orders INTO DATA(ls_order).
IF NOT line_exists( lt_valid_currencies[
currency_code = ls_order-Currency ] ).
APPEND VALUE #(
%tky = ls_order-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Currency { ls_order-Currency } is invalid| )
%element-Currency = if_abap_behv=>mk-on
) TO reported-salesorder.
APPEND VALUE #( %tky = ls_order-%tky ) TO failed-salesorder.
ENDIF.
ENDLOOP.
ENDMETHOD.

Collective Value Helps

For fields used in multiple views, central Value Helps can be defined:

-- Central Value Help Definition
@ObjectModel.usageType: {
sizeCategory: #S,
serviceQuality: #A,
dataClass: #CUSTOMIZING
}
define view entity ZI_CountryCollVH
as select from I_Country
{
key Country as CountryCode,
_Text.CountryName as CountryName
}

This can then be referenced in different views:

-- In View 1
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_CountryCollVH', element: 'CountryCode' }
}]
ShipToCountry,
-- In View 2
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_CountryCollVH', element: 'CountryCode' }
}]
BillToCountry,

Common Errors and Solutions

Error 1: Value Help Shows No Data

Symptom: The Value Help dialog opens but is empty.

Cause: The Value Help entity has no data or an incorrect filter.

Solution:

-- Check with SE16/ADT
SELECT * FROM zi_customerVH.
-- Remove or correct filter
define view entity ZI_CustomerVH as select from zcustomer
{
key customer_id as CustomerId
}
-- Check WHERE clause

Error 2: Additional Fields Are Not Filled

Symptom: The main field is filled, but additionalBinding fields remain empty.

Cause: Field names don’t match or usage: #RESULT is missing.

Solution:

additionalBinding: [{
element: 'CustomerName', -- Must exactly match field name in VH Entity
localElement: 'CustomerName', -- Must exactly match field name in Projection
usage: #RESULT -- Don't forget!
}]

Error 3: Cascading Doesn’t Work

Symptom: Dependent Value Help shows all values, not just filtered ones.

Cause: The filter field is missing in the Value Help entity.

Solution:

-- The VH Entity must contain the filter field
define view entity ZI_RegionVH as select from zregion
{
key region_code as RegionCode,
region_name as RegionName,
country_code as CountryCode -- This field is needed for filtering
}

Error 4: Performance Problems

Symptom: Value Help loads slowly or causes timeouts.

Cause: Large data volume without pagination or missing indexes.

Solution:

-- Set size category
@ObjectModel.resultSet.sizeCategory: #XS -- <100 entries
@ObjectModel.resultSet.sizeCategory: #S -- <1000 entries
-- Optimize search for typeahead
@Search.searchable: true
define view entity ZI_LargeDataVH
{
@Search.defaultSearchElement: true
@Search.ranking: #HIGH
key KeyField,
@Search.defaultSearchElement: true
TextField
}

Error 5: Validation Errors for Valid Values

Symptom: Input is rejected as invalid even though it exists in the Value Help.

Cause: Case sensitivity or leading/trailing whitespace.

Solution:

-- In the Value Help Entity
define view entity ZI_StatusVH as select from zstatus
{
key upper( status_code ) as StatusCode, -- Case-insensitive
status_text as StatusText
}

Error 6: Value Help Doesn’t Open

Symptom: No Value Help icon or dialog.

Cause: The annotation is on the wrong field or the entity doesn’t exist.

Solution:

-- Annotation must be on the editable field
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_CustomerVH', element: 'CustomerId' } -- Check entity name
}]
CustomerId, -- Not on calculated or virtual fields

Advanced Techniques

Distinct Values

For fields with duplicates:

@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_OrderStatusVH', element: 'Status' },
distinctValues: true
}]
Status,

Text Arrangement for Value Helps

@ObjectModel.text.element: ['StatusText']
@UI.textArrangement: #TEXT_FIRST
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_StatusVH', element: 'StatusCode' }
}]
StatusCode,

Value Help with Association

@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_CustomerVH' },
association: '_Customer'
}]
@ObjectModel.foreignKey.association: '_Customer'
CustomerId,
_Customer

Summary

FeatureAnnotation/Property
Basic Value Help@Consumption.valueHelpDefinition
FilteringadditionalBinding with usage: #FILTER
Return fieldsadditionalBinding with usage: #RESULT
CascadingCombination of #FILTER on dependent fields
ValidationuseForValidation: true
Multiple VHArray with different qualifier
Performance@ObjectModel.resultSet.sizeCategory

Value Helps are a powerful tool for user-friendly Fiori applications. With the right combination of CDS annotations, complex scenarios like dependent value helps and automatic field transfers can be implemented entirely declaratively.

  • CDS Annotations - All CDS annotations overview
  • RAP Basics - RESTful ABAP Programming fundamentals
  • Search Helps - Classic search helps in ABAP