Enabling Multiline Editing Capabalities in RAP

Estimated read time 13 min read

Introduction 

To enable multi-inline editing also for default root view entities, RAP offers the solution to model a technical root entity with just one instance, from which you can navigate to its object page. This singleton pattern provides a single entrance point to all master data instances. Multi-inline-edit capabilities are always necessary if you want the end user of a UI app to be able to edit, add, and delete all instances directly on a Fiori UI list report without navigating to the object page of one instance. It is always relevant for customizing and maintaining complete table data. Multi-inline capabilities on the UI represent the same feature scope as transaction SM30 in SAP GUI. 

Following Steps to enable Multiline Editing with Singleton instance 

 

Step 1: Create Custom Table. 

Step 2: Create Interface view on top of table (Child Entity) 

Step 3: Create root view entity With Reference to standard view 

step 4: Create Consumption view on top of root view and add Metadata. 

step 5: Create Consumption view on top of child view and add Metadata. 

step 6: create behavior definition on top of base root view (mapping) 

                make left out join from root view entity to the child table to get all the fields. 

step 7: create behavior definition for root consumption view 

                make application as draft enable 

step 8: create draft table for root table 

step 9: create draft table for child table. 

step 10: Create Service Definition for root consumption view 

step 11: Create Service Binding 

                  Preview application 

 

Step 1: Create Custom Table. 

 

@EndUserText.label : ‘Emplyoyee Data’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zemp_a {
key employee_id : abap.char(10) not null;
first_name : abap.char(50);
last_name : abap.char(50);
department : abap.char(20);
joining_date : abap.dats;
is_active : abap.char(1);
changed_by : abap.char(12);
local_last_changed_at : abp_locinst_lastchange_tstmpl;
changed_at : abp_lastchange_tstmpl;

 

Step 2: Create Interface view on top of table (Child Entity) 

 

@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Employee Interface’
//@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZI_EMP_AR as select from zemp_a
association to parent ZI_SINGLETONE_AR as _Semp
on $projection.EmpSingleton = _Semp.EmpSingleton
{
@EndUserText.label : ‘Employee ID’
key employee_id as EmployeeId,
1 as EmpSingleton,
@EndUserText.label: ‘First Name’
first_name as FirstName,
@EndUserText.label: ‘Last Name’
last_name as LastName,
@EndUserText.label: ‘Department’
department as Department,
@EndUserText.label: ‘Joining Date’
joining_date as JoiningDate,
@EndUserText.label: ‘Status’
is_active as IsActive,
@Semantics.user.lastChangedBy: true
changed_by as ChangedBy,
// ETag Field
@Semantics.systemDateTime.localInstanceLastChangedAt: true
local_last_changed_at as LocalLastChangedAt,
// Total ETag Field
@Semantics.systemDateTime.lastChangedAt: true
changed_at as ChangedAt,
_Semp
}

 

Step 3: Create root view entity (Singleton) With Reference to standard view. 

            make left outer join in the root view entity to access all fields from the employee table .

 

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Employee Singletone Interface’
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZI_SINGLETONE_AR as select from I_Language
left outer join zemp_a as zemp on 1 = 1 // to get all the field from the table
composition[ 0..* ] of ZI_EMP_AR as _EMP
{
key 1 as EmpSingleton,
max(zemp.changed_at) as maxChangedAt, //Done for total etag
_EMP
}
where I_Language.Language = $session.system_language

 

step 4: Create Consumption view on top of root view. 

 

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption view for Singletone Employee’
@Metadata.ignorePropagatedAnnotations: true
@UI.headerInfo: {
typeName: ‘Manage Employee’,
typeNamePlural: ‘Employee Singleton’,
title: {
type: #STANDARD,
value: ‘EmpSingleton’,
targetElement: ‘_EMP’
} }
define root view entity ZC_SINGLETONE
provider contract transactional_query
as projection on ZI_SINGLETONE_AR
{
@UI.facet: [{
purpose: #STANDARD,
parentId: ”,
position: 10,
label: ‘Employee Multil inline Edit’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_EMP’
}]
@UI.lineItem: [{ position: 10 }]
key EmpSingleton,
maxChangedAt, //done for total etag field
/* Associations */
_EMP : redirected to composition child ZC_EMP_AR

 

step 5: Create Consumption view on top of child view. 

 

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption view for Employees’
//@Metadata.ignorePropagatedAnnotations: true
@UI: { headerInfo: {
typeName: ‘Employee’,
typeNamePlural: ‘Employees’,
title: {
type: #STANDARD,
label: ‘Employee’,
value: ‘EmployeeId’
} }
}
define view entity ZC_EMP_AR
as projection on ZI_EMP_AR
{
@UI.facet: [{
type:#IDENTIFICATION_REFERENCE
}]
@UI:{ lineItem: [{ position: 10 }], identification: [{ position: 10 }] }
key EmployeeId,
// @ui:{ lineItem: [{ position: 20 }], identification: [{ position: 20 }] }
EmpSingleton,
@UI:{ lineItem: [{ position: 30 }], identification: [{ position: 30 }] }
FirstName,
@UI:{ lineItem: [{ position: 40 }], identification: [{ position: 40 }] }
LastName,
@UI:{ lineItem: [{ position: 50 }], identification: [{ position: 50 }] }
Department,
@UI:{ lineItem: [{ position: 60 }], identification: [{ position: 60 }] }
JoiningDate,
@UI:{ lineItem: [{ position: 70 }], identification: [{ position: 70 }] }
IsActive,
// @ui:{ lineItem: [{ position: 80 }], identification: [{ position: 80 }] }
// ChangedBy,
// LocalLastChangedAt,
// ChangedAt,
_Semp : redirected to parent ZC_SINGLETONE
}

 

step 6: create behavior definition on top of base root view (mapping) 

 

managed implementation in class zbp_i_singletone_ar unique;

strict ( 2 );

with draft;

define behavior for ZI_SINGLETONE_AR //alias <alias_name>

with unmanaged save // when we dont want save data to table then defin with unmanaged save

draft table ZDT_SINGLETONE

//persistent table t002

lock master

total etag maxChangedAt

authorization master ( instance )

//etag master <field_name>

##draft_op_not_required //to hide the warnings, create uptade, delete

{

// dont want modify the data for root entity

// create;

// update;

// delete;

field ( readonly ) EmpSingleton;

association _EMP { create; with draft; }

draft action Edit;

draft action Activate optimized;

draft action Discard;

draft action Resume;

draft determine action Prepare;

}

define behavior for ZI_EMP_AR //alias <alias_name>

persistent table zemp_a

draft table ZDT_EMP_AR

lock dependent by _Semp

authorization dependent by _Semp

etag master LocalLastChangedAt

{

update;

delete;

field ( mandatory : create, readonly :update ) EmployeeId;

field ( readonly ) EmpSingleton, ChangedAt, ChangedBy;

field ( mandatory ) FirstName;

association _Semp;

mapping for zemp_a

{

EmployeeId = employee_id;

FirstName = first_name;

LastName = last_name;

Department = department;

JoiningDate = joining_date;

IsActive = is_active;

ChangedBy = changed_by;

ChangedAt = changed_at;

LocalLastChangedAt = local_last_changed_at;

}

}

 

step 07: create behavior definition for root consumption view 

                 make application as draft enable .

 

rojection;
strict ( 2 );
use draft;
define behavior for ZC_SINGLETONE //alias <alias_name>

{
use action Edit;

use action Activate;
use action Discard;
use action Prepare;
use action Resume;
use association _EMP { create; with draft; }
}

define behavior for ZC_EMP_AR //alias <alias_name>
//use etag
{
use update;
use delete;
use association _Semp { with draft; }
}

 

step 08: create draft table for root table. 

 

@EndUserText.label : ‘Draft table for entity ZI_SINGLETONE_AR’

@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY

@AbapCatalog.tableCategory : #TRANSPARENT

@AbapCatalog.deliveryClass : #A

@AbapCatalog.dataMaintenance : #RESTRICTED
define table zdt_singletone {
key empsingleton : abap.int1 not null;
maxchangedat : abap.dec(21,7);

“%admin” : include sych_bdl_draft_admin_inc;

 

step 09: create draft table for child table. 

 

@EndUserText.label : ‘Draft table for entity ZI_EMP_AR’

@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY

@AbapCatalog.tableCategory : #TRANSPARENT

@AbapCatalog.deliveryClass : #A

@AbapCatalog.dataMaintenance : #RESTRICTED

define table zdt_emp_ar {

key employeeid : abap.char(10) not null;

empsingleton : abap.int1;

firstname : abap.char(50);

lastname : abap.char(50);

department : abap.char(20);

joiningdate : abap.dats;

isactive : abap.char(1);

changedby : abap.char(12);

locallastchangedat : abp_locinst_lastchange_tstmpl;

changedat : abp_lastchange_tstmpl;

“%admin” : include sych_bdl_draft_admin_inc;

}

 

step 11: Create Service Definition for root consumption view 

 

@EndUserText.label: ‘Employee Data Maintainance’

define service ZSR_ENPLOYEE_DATA {

expose ZC_SINGLETONE;

expose ZC_EMP_AR;

}

 

step 11: Create Service Binding 

                  Preview application 

Click Singleton Data 

Click on Edit (Here you can edit multiple data and save it to the database table.) 

Conclusion 

Enabling multiline editing in RAP requires careful configuration of both the backend (CDS Views and Business Logic). Proper data types, UI components, and backend handling must be in place to ensure seamless interaction with multiline text fields. 

 

 

​ Introduction To enable multi-inline editing also for default root view entities, RAP offers the solution to model a technical root entity with just one instance, from which you can navigate to its object page. This singleton pattern provides a single entrance point to all master data instances. Multi-inline-edit capabilities are always necessary if you want the end user of a UI app to be able to edit, add, and delete all instances directly on a Fiori UI list report without navigating to the object page of one instance. It is always relevant for customizing and maintaining complete table data. Multi-inline capabilities on the UI represent the same feature scope as transaction SM30 in SAP GUI. Following Steps to enable Multiline Editing with Singleton instance  Step 1: Create Custom Table. Step 2: Create Interface view on top of table (Child Entity) Step 3: Create root view entity With Reference to standard view step 4: Create Consumption view on top of root view and add Metadata. step 5: Create Consumption view on top of child view and add Metadata. step 6: create behavior definition on top of base root view (mapping)                 make left out join from root view entity to the child table to get all the fields. step 7: create behavior definition for root consumption view                 make application as draft enable step 8: create draft table for root table step 9: create draft table for child table. step 10: Create Service Definition for root consumption view step 11: Create Service Binding                   Preview application  Step 1: Create Custom Table.  @EndUserText.label : ‘Emplyoyee Data’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zemp_a {
key employee_id : abap.char(10) not null;
first_name : abap.char(50);
last_name : abap.char(50);
department : abap.char(20);
joining_date : abap.dats;
is_active : abap.char(1);
changed_by : abap.char(12);
local_last_changed_at : abp_locinst_lastchange_tstmpl;
changed_at : abp_lastchange_tstmpl;  Step 2: Create Interface view on top of table (Child Entity)  @AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Employee Interface’
//@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZI_EMP_AR as select from zemp_a
association to parent ZI_SINGLETONE_AR as _Semp
on $projection.EmpSingleton = _Semp.EmpSingleton
{
@EndUserText.label : ‘Employee ID’
key employee_id as EmployeeId,
1 as EmpSingleton,
@EndUserText.label: ‘First Name’
first_name as FirstName,
@EndUserText.label: ‘Last Name’
last_name as LastName,
@EndUserText.label: ‘Department’
department as Department,
@EndUserText.label: ‘Joining Date’
joining_date as JoiningDate,
@EndUserText.label: ‘Status’
is_active as IsActive,
@Semantics.user.lastChangedBy: true
changed_by as ChangedBy,
// ETag Field
@Semantics.systemDateTime.localInstanceLastChangedAt: true
local_last_changed_at as LocalLastChangedAt,
// Total ETag Field
@Semantics.systemDateTime.lastChangedAt: true
changed_at as ChangedAt,
_Semp
}  Step 3: Create root view entity (Singleton) With Reference to standard view.             make left outer join in the root view entity to access all fields from the employee table . @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Employee Singletone Interface’
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZI_SINGLETONE_AR as select from I_Language
left outer join zemp_a as zemp on 1 = 1 // to get all the field from the table
composition[ 0..* ] of ZI_EMP_AR as _EMP
{
key 1 as EmpSingleton,
max(zemp.changed_at) as maxChangedAt, //Done for total etag
_EMP
}
where I_Language.Language = $session.system_language  step 4: Create Consumption view on top of root view.  @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption view for Singletone Employee’
@Metadata.ignorePropagatedAnnotations: true
@UI.headerInfo: {
typeName: ‘Manage Employee’,
typeNamePlural: ‘Employee Singleton’,
title: {
type: #STANDARD,
value: ‘EmpSingleton’,
targetElement: ‘_EMP’
} }
define root view entity ZC_SINGLETONE
provider contract transactional_query
as projection on ZI_SINGLETONE_AR
{
@UI.facet: [{
purpose: #STANDARD,
parentId: ”,
position: 10,
label: ‘Employee Multil inline Edit’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_EMP’
}]
@UI.lineItem: [{ position: 10 }]
key EmpSingleton,
maxChangedAt, //done for total etag field
/* Associations */
_EMP : redirected to composition child ZC_EMP_AR  step 5: Create Consumption view on top of child view.  @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption view for Employees’
//@Metadata.ignorePropagatedAnnotations: true
@UI: { headerInfo: {
typeName: ‘Employee’,
typeNamePlural: ‘Employees’,
title: {
type: #STANDARD,
label: ‘Employee’,
value: ‘EmployeeId’
} }
}
define view entity ZC_EMP_AR
as projection on ZI_EMP_AR
{
@UI.facet: [{
type:#IDENTIFICATION_REFERENCE
}]
@UI:{ lineItem: [{ position: 10 }], identification: [{ position: 10 }] }
key EmployeeId,
// @ui:{ lineItem: [{ position: 20 }], identification: [{ position: 20 }] }
EmpSingleton,
@UI:{ lineItem: [{ position: 30 }], identification: [{ position: 30 }] }
FirstName,
@UI:{ lineItem: [{ position: 40 }], identification: [{ position: 40 }] }
LastName,
@UI:{ lineItem: [{ position: 50 }], identification: [{ position: 50 }] }
Department,
@UI:{ lineItem: [{ position: 60 }], identification: [{ position: 60 }] }
JoiningDate,
@UI:{ lineItem: [{ position: 70 }], identification: [{ position: 70 }] }
IsActive,
// @ui:{ lineItem: [{ position: 80 }], identification: [{ position: 80 }] }
// ChangedBy,
// LocalLastChangedAt,
// ChangedAt,
_Semp : redirected to parent ZC_SINGLETONE
}  step 6: create behavior definition on top of base root view (mapping)  managed implementation in class zbp_i_singletone_ar unique;

strict ( 2 );

with draft;

define behavior for ZI_SINGLETONE_AR //alias <alias_name>

with unmanaged save // when we dont want save data to table then defin with unmanaged save

draft table ZDT_SINGLETONE

//persistent table t002

lock master

total etag maxChangedAt

authorization master ( instance )

//etag master <field_name>

##draft_op_not_required //to hide the warnings, create uptade, delete

{

// dont want modify the data for root entity

// create;

// update;

// delete;

field ( readonly ) EmpSingleton;

association _EMP { create; with draft; }

draft action Edit;

draft action Activate optimized;

draft action Discard;

draft action Resume;

draft determine action Prepare;

}

define behavior for ZI_EMP_AR //alias <alias_name>

persistent table zemp_a

draft table ZDT_EMP_AR

lock dependent by _Semp

authorization dependent by _Semp

etag master LocalLastChangedAt

{

update;

delete;

field ( mandatory : create, readonly :update ) EmployeeId;

field ( readonly ) EmpSingleton, ChangedAt, ChangedBy;

field ( mandatory ) FirstName;

association _Semp;

mapping for zemp_a

{

EmployeeId = employee_id;

FirstName = first_name;

LastName = last_name;

Department = department;

JoiningDate = joining_date;

IsActive = is_active;

ChangedBy = changed_by;

ChangedAt = changed_at;

LocalLastChangedAt = local_last_changed_at;

}

}  step 07: create behavior definition for root consumption view                  make application as draft enable . rojection;
strict ( 2 );
use draft;
define behavior for ZC_SINGLETONE //alias <alias_name>

{
use action Edit;

use action Activate;
use action Discard;
use action Prepare;
use action Resume;
use association _EMP { create; with draft; }
}

define behavior for ZC_EMP_AR //alias <alias_name>
//use etag
{
use update;
use delete;
use association _Semp { with draft; }
}  step 08: create draft table for root table.  @EndUserText.label : ‘Draft table for entity ZI_SINGLETONE_AR’

@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY

@AbapCatalog.tableCategory : #TRANSPARENT

@AbapCatalog.deliveryClass : #A

@AbapCatalog.dataMaintenance : #RESTRICTED
define table zdt_singletone {
key empsingleton : abap.int1 not null;
maxchangedat : abap.dec(21,7);

“%admin” : include sych_bdl_draft_admin_inc;  step 09: create draft table for child table.  @EndUserText.label : ‘Draft table for entity ZI_EMP_AR’

@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY

@AbapCatalog.tableCategory : #TRANSPARENT

@AbapCatalog.deliveryClass : #A

@AbapCatalog.dataMaintenance : #RESTRICTED

define table zdt_emp_ar {

key employeeid : abap.char(10) not null;

empsingleton : abap.int1;

firstname : abap.char(50);

lastname : abap.char(50);

department : abap.char(20);

joiningdate : abap.dats;

isactive : abap.char(1);

changedby : abap.char(12);

locallastchangedat : abp_locinst_lastchange_tstmpl;

changedat : abp_lastchange_tstmpl;

“%admin” : include sych_bdl_draft_admin_inc;

}  step 11: Create Service Definition for root consumption view  @EndUserText.label: ‘Employee Data Maintainance’

define service ZSR_ENPLOYEE_DATA {

expose ZC_SINGLETONE;

expose ZC_EMP_AR;

}  step 11: Create Service Binding                   Preview application Click Singleton Data Click on Edit (Here you can edit multiple data and save it to the database table.) Conclusion Enabling multiline editing in RAP requires careful configuration of both the backend (CDS Views and Business Logic). Proper data types, UI components, and backend handling must be in place to ensure seamless interaction with multiline text fields.     Read More Application Development Blog Posts articles 

#SAP

You May Also Like

More From Author