Make a field Dynamically Mandatory – Custom Solution
Disclaimer: This blog post was originally created internally and i apologize for any sarcasm or criticism that i unintentionally leave in the blog. It is my hope that this basic guide will assist anyone searching with creating dynamic mandatory fields by providing a clear and detailed description how to do it.
If you have not read the section about creating dynamic mandatory fields first then go do that now, otherwise if you have just read that or read it previously…
Welcome Back! In this section I will describe a custom solution to complete the dynamic mandatory field development done previously so that some existing SAP errors no longer plague you. To solve our woes we will implement a custom class, I will provide a file for this, however, be aware that some standard enhancements were made to allow some functionality to work. I will attempt to describe the custom class here but be aware that some modifications may need to be made to make it function perfectly. I have attempted to remove references that use standard code enhancements but there is the potential that some still exist.
Please note that this tutorial assumes the developer has a general understanding of UI components, context nodes, and their various getter methods. Also the developer has read the previous section and knows how to make a field dynamically mandatory.
As described the current SAP implementation(at least for the version we have) is flawed. Mandatory fields are checked in the DO_FINISH_INPUT and through the first configuration of the page… When you set the field as mandatory in the P Getter as previously shown this code will be called in the DO_PREPARE_OUTPUT method of your UI Component View Controller. This is going to be fine to load a page and set the field as mandatory first time round. Unfortunately, when another field changes, which forces the conditions of your mandatory field in the P getter the order of checking fails to identify that the mandatory states have changed. The reason is as follows(in a simplified roundabout description):
DO_PREPARE_OUTPUT (Calls P Getters setting up conditions) -> |User Input Changes| (Hopefully triggering your conditions) -> DO_FINISH_INPUT (Gets the current mandatory fields and applies the messages)
!– Page Refresh -!
DO_PREPARE_OUTPUT (Calls P Getters setting up conditions) -> |Page ready for user input again|…
The flaw here is that on first load the page checked the conditions and the fields are set as mandatory/not-mandatory, then the user makes some changes. Next the do_finish_input method is called which adds the messages but it uses the mandatory fields that it knows of since the page was loaded! There is no check to see if the conditions have changed, which may have modified the state of the mandatory fields. Now from here you can debug through and make necessary changes to get it to work for you. You can probably guess that your going to need to check the conditions again. Well this is going to be annoying to do every single time you want to configure a new view with some dynamic mandatory fields on it. To solve this issue i created a custom class.
NOTE: The following steps ONLY work for a totally custom view… IF you are enhancing a standard component you could copy the ZCL_BSP_VIEW_CONTROLLER class to a custom version and change IT’S super-class to be the same as the enhanced view controller.
Custom Controller Class
The custom controller class provides a bunch of functionality to reduce the need to re-create that functionality for each view for example the following features exist:
- Enhancement to determine if mandatory check is required.Can make use of the MV_GLOBAL_EVENT attribute.
- Enhancement to check ‘P Getters’ for registered context nodes prior to getting the empty mandatory fields which fixes the issue discussed below’
- Enhancement to remove messages for specific events e.g. EDIT
- Enhancement to create the view_group_context if it is initial.
- Enhancement to solve an issue where global messages don’t block save in overview pages
Click here for the custom class as a .nugg file.
Step 1: Add the ZCL_BSP_VIEW_CONTROLLER class as a super class
Go to your class definition and navigate up the hierarchy until you locate the standard CL_BSP_WD_VIEW_CONTROLLER class sitting as the super class to your Z* class and ‘Change Inheritance’ of the class so that ZCL_BSP_VIEW_CONTROLLER is now the super class.
Step 2: Register the Context Node(s) that have the Dynamic Mandatory Fields
This step is required as otherwise the conditions will not be rechecked. You could imagine that if we didn’t have dynamic mandatory fields and just always rechecked every single attribute for every single context node on finish then efficiency would suffer. However, SAP standard does do exactly that in many other instances so you could choose not to care and follow their example. In this case, if using this class you need to register the node.
Right click the DO_FINISH_INPUT method of you controller class and ‘Redefine’ it (my screenshot shows this has already occurred).
Add the code to as shown to register the applicable context node(in my case its some PERSON node)
Bonus 1: Don’t Check on Certain Events
Now that we have our custom class in place some bonus functionality is available. As shown if we have an event where we don’t need to see irritating messages in the header we can remove the messages. In this case the fields are mandatory(shown with a red *) but we are not spammed with a message. But sometimes we might not even want to check for messages. For example the standard implementation kindly checks if the fields are mandatory for us when the user clicks the cancel button… Most circumstances dictate that there really is no need to check on a cancel event so we can override the IS_MANDATORY_CHECK_REQUIRED method and provide our own custom results. By default the custom class checks if the view is in display or edit mode for example before even checking for mandatory fields. We can include or remove that functionality once redefined or add our own criteria. Just remember to return a true or false result no matter what you choose to do…
The below example shows overriding the above mentioned method, including the check for display mode etc, and choosing not to check when the event is ‘CANCEL’.
Bonus 2: Add a Custom Error Message(* Removed as requires standard enhancement)
I won’t describe this as it used a standard enhancement to the CL_BSP_MESSAGES class to allow modifying a message by absolute ID(known as ‘dummy’ in the standard code).