RAP - Draft
In this article you will learn more about draft handling within a business object and how to implement it on an existing object.
Table of contents
What actually happens when a user stops working on the app and calls up the app again on another device? That's right, nothing of his current working status is available anymore. Today we want to show you how you can change this situation and give the user the opportunity to continue working on their second device without losing their entries.
Introduction
What is draft handling? This is a technique to save the current status in the backend in a kind of shadow table for the user after each step. The data is not initially in the table with the real data, it is a working status of the changes. To do this, you have to create the shadow table and expand the RAP business object in a few places.
Preparation
However, before we can get started with the change in the RAP, we need to create a prerequisite. A unique time stamp is required that describes the status of the last change, the so-called ETAG field. This must be present in every data table so that the system knows whether a data record has changed in the meantime. To do this, we add a new field to the partner table ZBS_DMO_PARTNER:
@EndUserText.label : 'Partner Data'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zbs_dmo_partner {
key client : abap.clnt not null;
key partner : abap.char(10) not null;
name : abap.char(60);
street : abap.char(80);
city : abap.char(60);
country : land1;
payment_currency : abap.cuky;
last_changed_at : timestampl;
}
At the end we add a new field "last_changed_at" with type "timestampl". This field will contain the information of the last change. After activating the table, we still have to extend the view stack of the RAP object and accept the field. The interface view now looks like this:
define root view entity ZBS_I_RAPPartner
as select from zbs_dmo_partner
{
key partner as PartnerNumber,
name as PartnerName,
street as Street,
city as City,
country as Country,
payment_currency as PaymentCurrency,
last_changed_at as LastChangedAt
}
First of all, we don't transfer it to the Consumption View because we don't want to output it, we only need the information for processing.
Behavior definition
In the next step, we can now tackle the actual expansion of the business object. To do this, we add the addition "with draft" to the behavior definition to activate draft handling. The further steps are now explained in the subsections.
with draft;
Draft table
Next, the draft table must be specified under the table of data. The system will issue a corresponding error message since the table does not yet exist. You can then use CTRL + 1 to create the table automatically.
The table has now been defined by the system as follows:
@EndUserText.label : 'Draft table for entity ZBS_I_RAPPARTNER'
@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zbs_dmo_dpartner {
key mandt : mandt not null;
key partnernumber : abap.char(10) not null;
key draftuuid : sdraft_uuid not null;
partnername : abap.char(60);
street : abap.char(80);
city : abap.char(60);
country : land1;
paymentcurrency : abap.cuky;
lastchangedat : timestampl;
"%admin" : include sych_bdl_draft_admin_inc;
}
The names of the fields correspond to the fields of the interface view. An additional element is added to the key and some administrative data is defined at the end of the table. The names of the fields should not be changed and should always correspond to the CDS views.
ETAG field
The new field must now be included in the mapping at the end of the behavior definition, and the "lock master" must be supplemented with the field, and a general ETAG must be defined as "master".
lock master total etag LastChangedAt
authorization master ( instance )
late numbering
etag master LastChangedAt
Actions
Another requirement is the implementation of the various draft actions provided by the framework. Validations that we have defined and that are executed before a draft is transferred to the productive table can be stored in the "Prepare" function.
draft action Resume;
draft action Edit;
draft action Activate;
draft action Discard;
draft determine action Prepare
{
validation validateKeyIsFilled;
validation validateCoreData;
}
New behavior definition
After all the adjustments, the new behavior definition now looks like this:
managed implementation in class zbp_bs_demo_rappartner unique;
strict;
with draft;
define behavior for ZBS_I_RAPPartner alias Partner
persistent table zbs_dmo_partner
draft table zbs_dmo_dpartner
lock master total etag LastChangedAt
authorization master ( instance )
late numbering
etag master LastChangedAt
{
create;
update;
delete ( features : global );
field ( readonly ) PartnerNumber;
draft action Resume;
draft action Edit;
draft action Activate;
draft action Discard;
draft determine action Prepare
{
validation validateKeyIsFilled;
validation validateCoreData;
}
validation validateKeyIsFilled on save { create; }
validation validateCoreData on save { create; field Country, PaymentCurrency; }
determination fillCurrency on modify { create; update; }
static action withPopup parameter ZBS_I_PopupEntity;
action ( features : instance ) fillEmptyStreets result [1] $self;
static action clearAllEmptyStreets;
factory action copyLine [1];
mapping for zbs_dmo_partner
{
PartnerNumber = partner;
PartnerName = name;
Street = street;
City = city;
Country = country;
PaymentCurrency = payment_currency;
LastChangedAt = last_changed_at;
}
}
Projection
So that the draft is also available via the app, it must also be given to the outside in the projection of the behavior definition. In addition, it is announced that Darft is used and the various actions are released. After adjustment, the projection now looks like this:
projection;
strict;
use draft;
define behavior for ZBS_C_RAPPartner alias Partner
{
use create;
use update;
use delete;
use action fillEmptyStreets;
use action clearAllEmptyStreets;
use action copyLine;
use action withPopup;
use action Edit;
use action Activate;
use action Discard;
use action Prepare;
use action Resume;
}
Behavior
What has actually changed in the app and what is the point? As soon as we open the app, we notice that another option has been added to the filter bar:
This allows the different drafts to be selected or you can only filter the "real" data sets. This filter is automatically gifted to you with draft handling. In the next step we take a look at the detail screen of a data set:
It is noticeable that there are now a few more buttons that provide us with some additional functions:
- Display Saved Version - Display of the original version of the dataset if changes have already been made.
- Discard Draft - The draft is removed from the draft table and the original record is the leading and only record.
As soon as you make a change to a field and switch focus to another field, a draft is created in the database and the information is saved:
When you click on the "Save" button, the data record from the draft table will be adopted as the new active version. However, if you just want to go back, you'll be asked what you want to do now:
If we set the point "Keep Draft" then the intermediate status will continue to be saved and we will end up back on the overview screen. If we now set the filter accordingly to our own entries, then our changed data set will be displayed:
Conclusion
You now know how to activate and use the draft in the business object. Furthermore, you know which requirements a table must meet so that Draft can also be activated. The function is available in many standard apps and completes the user experience in the Fiori context.