Olaf Pohlmann
Read all my blogsOne user interface element that the CRM 7.0 system offers and which is perhaps not so well known is the Guided Activity. It’s also known as Task-Based User Interface or Road Map. In this blog I would like to show how to create and use such a Guided Activity so you might see the potential for your own environment.
The use case
Let’s say we want to have an application in which a user can make changes to multiple orders. To guide the user we want to split up to process into the following tasks:
- Search for orders
- Modify the selected orders
- After the system checks the changes evaluate the result
- Save the changes
Setting up the application
Start the UI Component Workbench and create a new component with a main window. Assign the appropriate model using the Runtime Repository Editor and assign the main window to the ComponentInterface to make it available in the WebClient customizing.
To enable data binding within all views of the application it’s good practice to create a Custom Controller for this purpose. Let’s create one with the following context nodes:
A SEARCH-node with reference to the dynamic query object for orders
An ORDER-node for storing the collection of selected orders
Since we divided the process into four tasks we start by creating one view per task:
List view
Overview and Confirmation view
These two views are created similar to the List view but without adjustment of the editMode. The important settings are:
Now that we have the building blocks in place it’s time to create the actual view for the Guided Activity:
Roadmap view
Create a new view of type “Guided Activity Page” (there is no wizard this time). Create context nodes SEARCH and ORDER and bind these to the custom controller. Now include this view in the main window and assign the above created views to the Roadmap view. The Runtime Repository Editor should look like this:
Configuring the application
Before being able to test the application we need to configure each view. We start with the Roadmap view. Select all the views and provide a label for each step:
Implementing the business logic
But what is a good place to store the business logic? Looking at “Navigation Between Guided Activity Steps” in the SAP help you’ll see that the system provides two interfaces to influence the behavior: IF_BSP_DLC_PROCESS_CONTROL which the Roadmap view implements by default and interface IF_BSP_DLC_PROCESS_STEP which the individual steps might implement. So you have a choice here but I strongly recommend to use only the provided interface in the Roadmap view and in doing so keep the logic in one place at much as possible.
Method IS_POSSIBLE_TO_LEAVE_CURR_STEP is crucial because the system will check at each navigation attempt, by calling this method, whether the requested navigation is allowed. Within this method the system provides (through attribute ROADMAP_CONTROL information on the current and target step and provides methods to enable and disable steps.
To initialize the Guided Activity properly I want to disable the last two steps by default so they can be activated later if relevant. The following code in method DO_PREPARE_OUTPUT takes care of this:
super->do_prepare_output( iv_first_time ).
“When starting the roadmap deactivate direct navigation to the last two steps
if me->roadmap_control->get_active_item_number( ) = 1.
me->roadmap_control->set_item_disabled( 3 ).
me->roadmap_control->set_item_disabled( 4 ).
endif.
endmethod.
Now it’s time to implement the logic for each transition. I prefer to create a method per transition to get a nice and clear overview of the navigation possibilities. The code then looks something like:
“Concatenate the current and target step in one variable
case me->roadmap_control->get_active_item_number( ) && ‘-‘ && me->roadmap_control->get_target_item_number( ).
when `1-2`. “Search -> List
“Navigation is only allowed if orders have been found
if search_orders( ) = 0.
rv_result = abap_true.
“Activate the Overview step
me->roadmap_control->set_item_disabled( iv_item_number = 3 iv_disabled = abap_false ).
endif.
when `2-3`. “List -> Overview
“This navigation is always allowed
rv_result = abap_true.
if check_orders( ) = 0.
“Activate the Confirmation step if all changes can be processed
me->roadmap_control->set_item_disabled( iv_item_number = 4 iv_disabled = abap_false ).
endif.
when `3-4`. “Overview -> Confirmation
“This navigation is allowed since all checks have already been done in the previous step
rv_result = abap_true.
“Save the changes
if save_orders( ) = 0.
“Ready, no way back
me->roadmap_control->set_item_disabled( 1 ).
me->roadmap_control->set_item_disabled( 2 ).
me->roadmap_control->set_item_disabled( 3 ).
endif.
when `4-1` or `4-2` or `4-3`
or `3-1` or `3-2`
or `2-1`.
“Backwards navigation is always allowed
rv_result = abap_true.
“Deactivate the next step
me->roadmap_control->set_item_disabled( me->roadmap_control->get_active_item_number( ) + 1 ).
endcase.
endmethod.
The result
With all the navigation logic in place the happy flow of the Guided Activity is presented like this:
How to create a search view
As a bonus I want to show you how to convert an empty view into a search view in a few steps:
- Start by changing the inheritance of the view controller class. Check where the class inherits from CL_BSP_WD_VIEW_CONTROLLER and change it to CL_BSP_WD_ADVSEARCH_CONTROLLER.
- Similarly change the inheritance from the SEARCH-node from CL_BSP_WD_CONTEXT_NODE to CL_BSP_WD_CONTEXT_NODE_ASP.
- Lastly, provide the Search view with the following HTML-code:
<thtmlb:advancedSearch id = “search”
fieldMetadata = “<%= controller->get_dquery_definitions( ) %>”
header = “<%= SEARCH->get_param_struct_name( ) %>”
fieldNames = “<%= controller->get_possible_fields( ) %>”
values = “//SEARCH/parameters”
showMaxHits = “false” />
</thtmlb:searchArea>
Et voilĂ :
data:
lr_query type ref to cl_crm_bol_dquery_service,
lr_result type ref to if_bol_entity_col.
“Execute the query and store the result
lr_query ?= me->typed_context->search->collection_wrapper->get_current( ).
lr_result = lr_query->get_query_result( ).
me->typed_context->order->set_collection( lr_result ).
endmethod.