
Script: Recycling-Heroes - Validation and Determination (Contact) [016]
In this episode, we'll ensure that the entered data is properly validated and that we only accept complete records into our app. We'll also implement a first interface for loading address data and refresh th UI with side effects.
Table of contents
Introduction
Currently, we can create new data records in our application without validating fields. For example, the name of an employee should be defined as a required field, as we need it in our process. We also want to have a contact for this employee in case of emergency. If we create a data record here, for example, it will simply be saved, and the important information will be missing.
Definition
To do this, we first create the corresponding methods in our behavior definition. A validation starts with the keyword "VALIDATION", followed by the name of the validation. A validation should always be performed when saving to prevent incorrect data records from being saved. Finally, validation should be applied when a data record is created and updated. We will then copy the validation accordingly, as we want to create three different implementations.
We will also create a determination that begins with the keyword "DETERMINATION." This will later determine address data that we need in the process. The determination should always be performed when the data record is changed, both when it is created and when it is changed.
After the definition, we can create the methods using Quick Fix or CTRL + 1. The four methods are created in the behavior implementation, where we can then continue working.
Validation
Let's now implement the first validation as a prototype for the other cases. To do this, we want to define a helper method in our auxiliary class to read the data from the current request. In our validation, we first create an instance of the helper class and then call the method. Since this doesn't exist yet, we can create it using a quick fix. In the next step, we still need the correct type for passing the keys to the method. We get the element information via F2 and can then transfer the type to our class. We can then implement the READ ENTITY in the method. It's generally best not to read all fields, but only those required for validation. Since we want to return the result, we need to create a return type in the class. We get this from the element information in the result of the EML statement. Once the method is fully implemented, we can format it again with the ABAP Cleaner, then activate it and close the object, since we won't be making any further changes here.
Let's now begin implementing the validation logic. To do this, we go through the data records currently being checked. Here, it is sufficient to process the data records that currently contain errors. This means that in the WHERE condition, we restrict the search to records where email and phone are still empty, since at least one piece of information should be filled in. This means that all data records within the loop are faulty. First, we populate the FAILED structure to inform RAP that this data record is still faulty. All relevant keys are populated using the %TKY field, which means we have to write less for longer keys. Next, we want to provide the user with an error message; to do this, we need to populate the REPORTED structure. In the %MSG field, we create the error message that should be displayed in the UI. We set the severity to Error, which results in a red message in the UI. To create a message and keep it translatable, we create a new message in our component's message class. Once we have created and saved the text, we can populate the message variables in the validation.
Let's now test the current state of the validation and go to the UI. We create a new customer record and save it with the empty information. We now receive a corresponding error message in the UI above and via the message output.
At the moment, however, the user doesn't yet know which field is actually affected. Therefore, we want to highlight the two fields in the UI. To do this, we populate the corresponding elements in the Reported structure using the %ELEMENT. Here, we set the value for both fields to ON. If we now check the behavior again in the UI, the error message from above has disappeared. If we click directly on the error message, we are taken to the phone field in the UI. Both fields are highlighted in red in this case, so the user knows which information is still missing. To ensure the validation is now complete, we must restrict the contact type. Otherwise, the validation would apply to all records, but it is only intended for the customer.
Further Validations
Now, let's finalize the further validations in the object. To do this, we copy our validation as a template and fill in the remaining information. Since the key structure is not defined exactly the same, but contains the same fields, we add a CORRESPONDING as a mapping. We then adjust the checked fields so that this validation only applies to the employee. Since a different error message should appear here, we create an additional message and replace the current message in the method.
The third check should validate that a first and last name is defined for the customer and our employee. Therefore, we adjust the Where condition again and restrict the data. We also create a separate error message for this case and change the fields.
For the test, we switch to the UI and create a new employee. We leave all information blank and attempt to save the data record. We receive error messages for each section of the form and can use them to fill in the required fields, which are now highlighted in red on the form. Now we assign a name and an email address and save the entire data set.
Determination
For the determination, we now create a new interface. To do this, however, we first need a corresponding package in the hierarchy. To do this, we first define a general package for interfaces. Below this, we then create an interface that will determine address data.
To define the new interface, we use an IDE action in Eclipse. You can also find this as an open source project linked in the description. The action takes over the generation of the artifacts and establishes the various relationships between the classes. To do this, we first need a name and a description, which will be used to create the objects later. The instance name is important during processing. If all the data is correct so far, we generate the objects. Once the generation is complete, we receive an overview of the objects. From here, we can jump directly to the appropriate objects. You may need to confirm the dialog at this point to jump to the object.
Let's go through the objects and format them or look at their use. We can later pass test doubles via the injector without adjusting the actual logic. The factory creates decoupled objects so that we are separated from the actual implementation. This gives us the option of creating the real instance or a test double at runtime. In the interface, we define our API method, which we will call later. We then implement the method in the actual class. In this example, we first create a dummy implementation and map two postal codes to city and country. In a later video, we would then use a real API for this. In this example, we use Berlin and Cologne to provide data. After activation, we are finished with the interface.
In the actual implementation, we create an instance of the service that we will then use. Here, we can again copy the logic for determining the selected data records. In the next step, we call the API for each data record. Since the data records have different types, we need to map them to the target structure. Finally, we want to update the data records. To do this, we use the MODIFY ENTITY and pass the city and country for updating. To ensure that we only make changes when the conditions are met, we set a WHERE condition in the loop. The postal code should be filled in, and at least one of the two target fields should be empty.
Finally, let's test the determination in the UI. To do this, we create a new address and fill in the postal code. When we save the data record, the city and country are now determined and transferred to the fields.
Side Effects
There's one thing that bothers us right now: the data is only updated when we save. This means the user can't see whether the correct data was determined before saving. Therefore, we'll change the determination process so that it runs whenever the ZipCode field changes. We'll also implement a side effect on the field. This automatically updates the UI when the field is changed and the cursor leaves the field. To ensure the side effect is used, we must declare its use at the consumption level.
If we then go into the application and create a new address, we can fill the zip code with a new value. If we then change the field with the cursor, the city and country are automatically filled.
Summary
In today's episode, we have implemented additional checks in the UI to validate the completeness of the input. Depending on the input, we can use a determination to add further information without the user having to intervene. The side effects allow the changes to be displayed immediately in the UI; manual refreshing is no longer necessary. In the next episode we will build and deploy the application.
Thanks for watching and see you next time.
YouTube
Video