RAP Value Helps: Ayudas de Valores Basadas en Anotaciones en ABAP Cloud

Kategorie
RAP
Veröffentlicht
Autor
Johannes

Los Value Helps (ayudas de valores) son un elemento central de cualquier aplicación Fiori. Permiten a los usuarios seleccionar cómodamente valores de listas predefinidas. En RAP los Value Helps se definen declarativamente mediante anotaciones CDS, sin escribir una sola línea de código UI.

Concepto Básico de Value Helps

Los Value Helps en RAP se basan en la anotación @Consumption.valueHelpDefinition. Esta vincula un campo con una entidad CDS que sirve como lista de valores.

Value Help Simple

La configuración mínima consiste en la anotación en el campo objetivo:

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

Esta configuración muestra automáticamente una ayuda de valores con todos los clientes de ZI_Customer cuando el usuario hace clic en el campo CustomerId.

Estructura de la Anotación

@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_ValueHelpEntity', -- Nombre de la entidad CDS
element: 'KeyField' -- Campo clave (opcional)
},
qualifier: 'MyValueHelp', -- Identificador único
label: 'Selección de Cliente', -- Título del diálogo
useForValidation: true, -- Activar validación
additionalBinding: [{...}], -- Asignaciones de campos adicionales
distinctValues: true -- Solo valores únicos
}]

Diseño de Entidad Value Help

La entidad que sirve como Value Help debe estar optimizada específicamente para este propósito:

@EndUserText.label: 'Value Help de Clientes'
@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 = ''

Mejores Prácticas para Entidades Value Help

AspectoRecomendación
Tamaño@ObjectModel.resultSet.sizeCategory: #XS para listas pequeñas
Búsqueda@Search.searchable para Typeahead
FiltroCláusula WHERE para entradas inválidas
CamposExponer solo campos relevantes

Diferencia: Value Helps Simples vs. Complejos

Value Help Simple

Muestra solo el campo clave y opcionalmente un texto descriptivo:

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

La entidad Value Help:

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

Value Help Complejo

Contiene múltiples columnas, filtros y campos de retorno adicionales:

@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 con Condiciones de Filtro

Los filtros restringen los valores mostrados. Hay dos tipos: filtros estáticos y dinámicos.

Filtro Estático

Filtra el Value Help a valores fijos:

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

Este Value Help muestra solo productos con ProductType = 'FINISHED'.

Filtro Dinámico (dependiente de otros campos)

El filtro se basa en el valor de otro campo:

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
}

Aquí solo se muestran los proveedores que pertenecen a la organización de compras seleccionada.

Combinar Múltiples Filtros

@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 (Ayudas de Valores Dependientes)

Los Cascading Value Helps son dependientes entre sí: la selección en un Value Help influye en las opciones de otro.

Ejemplo: País -> Región -> Ciudad

define view entity ZC_Address
as projection on ZI_Address
{
key AddressId,
-- 1er Nivel: País
@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_CountryVH',
element: 'CountryCode'
},
additionalBinding: [{
element: 'CountryName',
localElement: 'CountryName',
usage: #RESULT
}]
}]
CountryCode,
CountryName,
-- 2do Nivel: Región (filtrada por País)
@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_RegionVH',
element: 'RegionCode'
},
additionalBinding: [{
element: 'CountryCode',
localElement: 'CountryCode',
usage: #FILTER
}, {
element: 'RegionName',
localElement: 'RegionName',
usage: #RESULT
}]
}]
RegionCode,
RegionName,
-- 3er Nivel: Ciudad (filtrada por Región)
@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_CityVH',
element: 'CityCode'
},
additionalBinding: [{
element: 'RegionCode',
localElement: 'RegionCode',
usage: #FILTER
}, {
element: 'CityName',
localElement: 'CityName',
usage: #RESULT
}]
}]
CityCode,
CityName
}

Entidades Value Help para Cascading

-- Países
define view entity ZI_CountryVH
as select from zcountry
{
key country_code as CountryCode,
country_name as CountryName
}
-- Regiones (con clave foránea a País)
define view entity ZI_RegionVH
as select from zregion
{
key region_code as RegionCode,
region_name as RegionName,
country_code as CountryCode -- Criterio de filtro
}
-- Ciudades (con clave foránea a Región)
define view entity ZI_CityVH
as select from zcity
{
key city_code as CityCode,
city_name as CityName,
region_code as RegionCode -- Criterio de filtro
}

Value Help con Campos de Salida Adicionales

Los campos de salida adicionales transfieren automáticamente valores del Value Help a otros campos de la entidad.

Ejemplo: Datos Maestros de Material

define view entity ZC_SalesOrderItem
as projection on ZI_SalesOrderItem
{
key SalesOrderId,
key ItemNumber,
@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_MaterialVH',
element: 'MaterialNumber'
},
additionalBinding: [
-- Campos de retorno
{ element: 'MaterialDescription', localElement: 'MaterialText', usage: #RESULT },
{ element: 'BaseUnit', localElement: 'Unit', usage: #RESULT },
{ element: 'MaterialGroup', localElement: 'MatGroup', usage: #RESULT },
{ element: 'GrossWeight', localElement: 'Weight', usage: #RESULT },
-- Simultáneamente como filtro
{ element: 'SalesOrg', localElement: 'SalesOrg', usage: #FILTER_AND_RESULT }
]
}]
MaterialNumber,
MaterialText,
Unit,
MatGroup,
Weight,
SalesOrg,
Quantity,
NetPrice
}

Opciones de Usage

ValorDescripción
#RESULTEl valor se devuelve
#FILTEREl valor sirve como filtro
#FILTER_AND_RESULTAmbos combinados

Ejemplo Práctico: Cliente con Dirección

@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,

Múltiples Value Helps para un Campo

Un campo puede tener múltiples Value Helps alternativos:

@Consumption.valueHelpDefinition: [
{
entity: { name: 'ZI_CustomerVH', element: 'CustomerId' },
qualifier: 'AllCustomers',
label: 'Todos los Clientes'
},
{
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: 'Usados Recientemente'
}
]
CustomerId,

El usuario puede elegir entre los Value Helps.

Validación con Value Helps

La anotación useForValidation verifica los valores ingresados contra el Value Help:

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

Para entradas inválidas, Fiori muestra automáticamente un mensaje de error.

Validación en la Behavior Definition

Además de la validación UI, también debe validarse en el backend:

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 = |Moneda { ls_order-Currency } es inválida| )
%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

Para campos que se usan en múltiples views, se pueden definir Value Helps centrales:

-- Definición central de Value Help
@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
}

Esta puede referenciarse en diferentes views:

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

Errores Típicos y Soluciones

Error 1: Value Help no Muestra Datos

Síntoma: El diálogo del Value Help se abre, pero está vacío.

Causa: La entidad Value Help no tiene datos o tiene un filtro incorrecto.

Solución:

-- Verificar con SE16/ADT
SELECT * FROM zi_customerVH.
-- Eliminar o corregir filtro
define view entity ZI_CustomerVH as select from zcustomer
{
key customer_id as CustomerId
}
-- Verificar cláusula WHERE

Error 2: Campos Adicionales no se Llenan

Síntoma: El campo principal se llena, pero los campos de additionalBinding quedan vacíos.

Causa: Los nombres de campo no coinciden o falta usage: #RESULT.

Solución:

additionalBinding: [{
element: 'CustomerName', -- Debe coincidir exactamente con el nombre en la Entidad VH
localElement: 'CustomerName', -- Debe coincidir exactamente con el nombre en la Projection
usage: #RESULT -- ¡No olvidar!
}]

Error 3: Cascading no Funciona

Síntoma: El Value Help dependiente muestra todos los valores, no solo los filtrados.

Causa: El campo de filtro falta en la entidad Value Help.

Solución:

-- La entidad VH debe contener el campo de filtro
define view entity ZI_RegionVH as select from zregion
{
key region_code as RegionCode,
region_name as RegionName,
country_code as CountryCode -- Este campo se necesita para filtrar
}

Error 4: Problemas de Performance

Síntoma: Value Help carga lento o causa timeouts.

Causa: Gran cantidad de datos sin paginación o índices faltantes.

Solución:

-- Establecer categoría de tamaño
@ObjectModel.resultSet.sizeCategory: #XS -- <100 entradas
@ObjectModel.resultSet.sizeCategory: #S -- <1000 entradas
-- Optimizar búsqueda para Typeahead
@Search.searchable: true
define view entity ZI_LargeDataVH
{
@Search.defaultSearchElement: true
@Search.ranking: #HIGH
key KeyField,
@Search.defaultSearchElement: true
TextField
}

Error 5: Errores de Validación en Valores Válidos

Síntoma: La entrada se rechaza como inválida, aunque existe en el Value Help.

Causa: Sensibilidad a mayúsculas/minúsculas o espacios al inicio/final.

Solución:

-- En la entidad Value Help
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 no se Abre

Síntoma: No hay icono de Value Help ni diálogo.

Causa: La anotación está en el campo incorrecto o la entidad no existe.

Solución:

-- La anotación debe estar en el campo editable
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_CustomerVH', element: 'CustomerId' } -- Verificar nombre de entidad
}]
CustomerId, -- No en campos calculados o virtuales

Técnicas Avanzadas

Distinct Values

Para campos con duplicados:

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

Text-Arrangement para Value Helps

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

Value Help con Asociación

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

Resumen

CaracterísticaAnotación/Propiedad
Value Help Básico@Consumption.valueHelpDefinition
FiltradoadditionalBinding con usage: #FILTER
Campos de RetornoadditionalBinding con usage: #RESULT
CascadingCombinación de #FILTER en campos dependientes
ValidaciónuseForValidation: true
Múltiples VHArray con diferentes qualifier
Performance@ObjectModel.resultSet.sizeCategory

Los Value Helps son una herramienta poderosa para aplicaciones Fiori amigables. Con la combinación correcta de anotaciones CDS se pueden implementar escenarios complejos como ayudas de valores dependientes y transferencia automática de campos de forma completamente declarativa.

Temas Relacionados