SAP Tutorial: Complete CAP Java Part 11
Adding a custom action to a Fiori Elements page, problems with the sample app’s implementation
Contents
- Previous: CQN Analyzers, extracting values from CQN statements, saving to the database, and returning responses
- Current: Adding a custom action to a Fiori Elements page, problems with the sample app’s implementation
- Next: Adding a custom components to Fiori Elements, basic SAPUI5 dialog setup
Here we are at Part 11 of the Complete CAP Java tutorial series, where I show you the ins and outs of developing applications with SAP’s CAP for Java framework by rebuilding SAP’s sample Bookshop application step by step while adding a few improvements to it along the way. In the previous several episodes we’ve been working on implementing a custom action in a Fiori Elements List Report that allows us to add a review to a Book entity.
For reference, here’s our target:
And here’s what we have so far:
So far we’ve managed to implement the basic backend logic for our Add Review action. Now we need to use CDS to specify the UI for the action. Let’s learn how to do that.
Step 1: Defining the Add Review Button in CDS
You’ll recall from earlier episodes in this series that we’ve been defining the features of our Fiori Elements UI using cds in app/browse/fiori-service.cds, so we’ll add the following changes to that file. As we saw from the example above, the Add Review button exists as a column of the table, so we need to define it as column like we did for the other data in the table — by adding another item to the LineItem annotation. It’ll look like this below:
You’ll notice that, like the Rating field above, we need to specify the type as UI.DataFieldForAnnotation. Without this, we would get the default type of DataField, which simply displays a value; DataFieldForAnnotation says that we will define was goes here using a different annotation. We specified that annotation using the Target property, UI.FieldGroup#AddReview. The part before the hashtag specifies what type of annotation will contain the information about the target; the part after the hashtag specifies the name of the annotation, which will be provided by us. Notice also that we didn’t provide a label annotation, which would ordinarily give us a column label. This is because for some reason Fiori Elements ignores the label property for this kind of LineItem, so there’s no need to include it.
Just trying to start up the application now will lead to an error though because we haven’t defined the FieldGroup yet. Let’s do that now.
In the same file we add the FieldGroup annotation followed by #AddReview. Now our annotation from above has something to find. Next we provide an object with one attribute: Data. Data consists of an array of objects with the properties $Type, Label, Action, and InvocationGrouping. We could presumably add as many of these objects as we like, for example to add multiple buttons to this single column. We only need one here, however so we’ll leave it at that.
As a type we specify UI.DataFieldForAction. This tells Fiori Elements that this button is going to be linked to an oData action like the one we defined in the last few episodes of this series. Label describes what the text of the button that this will generate will be. This is different from the LineItem label, which determines what the label for a column will be. Next we specify Action as <NameOfService>.<NameOfAction>, so CatalogService.addReview. Finally, we set the InvocationGrouping to #Isolated. What this does is specify the error handling of this action. Isolated means if multiple actions are executed at once and one of them fails then the others should still be allowed to complete. We could also choose ChangeSet to specify that if one fails they should all fail. In our case we don’t need the ChangeSet behavior since we aren’t firing off a set of these actions at the same time.
Let’s take a look at the result:
And we can even click the button to display a form for to input the rating information:
Notice that there’s something we’re still missing here: the field labels are all just the names of the variables. We should provide proper labels for them. Let’s do that. Go to app/browse/fiori-service.cds and add the following lines:
Now if you boot the app again, you’ll have proper labels:
Now go ahead and try adding a Review. It works…kind of. But we have some problems. Let’s talk about them.
Step 2: Problems With the Sample App’s Implementation
Problem 1: The Rating Field Input
The UI is just not good for our purposes here. We have a 0–5 rating system, but the user can type in anything they want. Such a limited number of options would be better served by a radio button group or a dropdown menu. Here though the user is left to just type in values and see what works. Luckily, thanks to the input types we specified, at the very least we do get an a validation error if we type in a non-integer value as shown below:
But look at this! Even though we specified our enum type as an input, look what happens when we input a number that’s out of range:
What’s the deal? Well, if we check how the CDS compiles to edmx, we can find the answer (run cds compile srv/cat-service.cds --to edmx):
That’s right: apparently enum types are not currently supported by CDS for actions, so they just compile to the overall type of the enum. Since we specified an integer enum, it just becomes an integer.
Not only that, our action circumvents CAP’s normal validation rules, so if we submit our review with an invalid number, it still get’s written to the database! Try it to see for yourself. How can we solve these issues?
CAP Sample App’s Solution
In the CAP Sample App, they solve the validation issue by simply adding a range validation check manually to ensure that users don’t input the wrong value, and if they do then then an error message is returned to the frontend to be displayed. This does indeed solve the validation issue, but it also means that we have to maintain the validation specification in two different places , those being in the CDS for the standard Review creation method and in the Java for our custom Review creating action. Thus, if we decided to change our reviews to allow only 1–5 instead of 0–5, we’d have to update the app in two places. As you can imagine, that’s very error prone.
As for the style of the input, the CAP Sample app, as you have seen, just leaves it as it is. This is no good. If we’re going to make a high-quality, user-friendly app for our users, we can’t accept the CAP Sample app’s solution.
Problem 2: The Text Field
If we check the Title field, all is well — it will block us from submitting a title that’s more than 100 characters. The Text field will also prevent us from submitting text more than 1000 characters, so that’s also fine. The validations are therefore no problem, but we do have an issue with the text field: it is much too small for adding a full comment. The CAP Sample app just leaves this as it is, but again if we’re actually building an app for real users, this is unacceptable. How can we improve it?
I have two possible solutions.
Solution 1: Don’t Try Creating Entities With an Action
Fiori Elements simply isn’t designed with out of the box functionality for creating entities through actions, so we have to come up with workarounds that can cause issues for code maintainability and also simply take time to implement. However, since the Review is a child of Book, we can simply use standard Fiori Elements functionality to create a Review from the Book Object Page (which we haven’t configured yet) rather than doing it on a List Report. If we do this, then we can leverage CAP and Fiori Elements standard features to increase the speed of development while also avoiding the maintenance overhead from the Sample App’s custom solution. I believe this is the best solution. I’ll show you how to implement this when we get along to configuring the Object Page. For now, since we’re just working on the List Report, we’ll leave that aside for a while.
Solution 2: Create a Custom Component
If we have a use case where we really need to have a more configurable dialog for an action on the List Report page, then our best option is going to make a custom SAPUI5 component and to inject it into our Fiori Elements app using an extension point.
This solution increases development time and maintenance costs, so we really shouldn’t do this unless its absolutely necessary. In our case, it’s not absolutely necessary so this solution should be avoided. However, for intellectual curiosity and in case you do have a use case where this is needed, let’s go ahead and implement our solution with a custom component.
However, this post will be far too long if we jump into that now, so we’re going to leave this aside for now and get started on that next week!
Conclusion
In this installment we learned how to use CDS to specify the UI for our custom action for adding a review. However, we also found some significant issues with the implementation found in the CAP Sample app and discussed some possible solutions. Next week we’re going to implement one of those solutions: a custom SAPUI5 component that will give us more fine-tuned control over the UI and input validations. Stay tuned!
Was anything unclear in this tutorial? Leave a question below and I’ll get back to you as soon as possible. Was anything incorrect? Please leave a comment below and let me know (a source for the correction would be most helpful). Thanks for your comments!
Support
Did you like this blog? Want to make sure I can keep creating them? Then consider subscribing on Patreon!