Trying to understand how abap webdynpro works, i stumbled upon
by Thomas Jung (/people/thomas.jung/blog)
about recreating transaction SE16 in a webdynpro application.I found it
very good, but as many step-by-step tutorials is too concerned with how
you do something than to explain why you are doing it.
So I tried to
get the same job done in a slightly different way, both about the
coding and the comments on what’s going on.The main reason for which
I’m writing this is to see if my understanding of this technology is
good enough to explain it, but I hope it’ll be useful to other users
of the application described below is available as saplink (http://code.google.com/p/saplink/) packages (see the readme file before importing, there are a couple of minor issues with saplink) on
, so here you’ll only find a few snippets.
note that to keep things simple this application doesn’ t have user
rights management and only uses very basic error handling.
Create the application
start creating a new webdynpro component ZSE16_URB with a window named
MAIN and a webdynpro application with the same name. Of course the
applicartion will use the component I just created:
Not much to understand here, basically I only set a few names and descriptions.
If you have trouble importing the application slinkee, just copy whatr you see above and save it, it’s a pretty simple task.
Set up navigation path
The application has a single window with three views, with an interface that mimics the original SE16.
create the three views and leave them empty, with only the inbound and
outbound plugs required to manage a forward flow and backward one:
table selection view (TABSEL) <-> main selection screen (SELSCR) <-> output list (LIST)
Then I set up the navigation path in the window:
The default view is TABSEL.
The actual navigation will be activated in the view event handlers using methods like wd_this->
), where the bold part is the name of the plug. Those methods could
have parameters too, but I don’t need any in this case because most of
the data is handled globally in the componentcontroller.
Every inbound plug has a handler method such as
HANDLEBACK, in which you could eventually add parameters like what you defined in the matching outbound plug(s).
this point I have a valid application, accessible through the URL shown
in the webdynpro application.Of course it still doesn’t do anything but
display an empty screen.
Before I start coding, in order to define language dependent texts I
have to define an helper class. To do so I simply enter the name of my
helper class ZCL_SE16_URB_ASSIST in the component header and let the
system authomatically create it when saving the modified
helper class is very handy because an instance of this class is created
during the application startup and is accessible almost everywhere in
the component, so it acts a little like a global data and code
repository.Abuse of this feature may be very dangerous, an most
programming shortcuts, so I decided to only use it for messaging.
then added a public message manager attribute (MESSMAN), a method to
set it (DO_INIT), and another to show error messages using their
IDs.The latter is handy because the ‘some text'(T01) idiom doesn’t work
in a webdynpro environment, except in the helper class methods.
A little warning on the MESSMAN trick: I tested this on my system, but
I don’t really know what I’m doing: if the message manager can change
during a session it may be a BAD idea to store it in the helper class.
the job of DO_INIT in the constructor would be nicer, but I don’t think
it’s possible to get it there, let alone how to do it.
Component controller attributes
I defined three attributes:
a reference of the context element. Used as a shortcut to move data
from SE16_PARMS to the context and back.Wouldn’t be needed if I could
figure out bind them together properly.
of type ZCL_SE16_CORE, which does most of the work. I described
this class in a later blog (A class for dynamic queries) to keep this entry focused on webdynpro
technology.Later I’ll add a few methods to this controller to expose to the views the functionality provided by the attributes above.
way to get the same result is to put the attributes above into the
helper class: this way I could use them directly from the views and
spare a few lines of code.While this approach wouldn’t hurt too much in
a toy application like this, it would be a terrible idea in the real
world, so I’ll try to behave like a nice guy and code as I’m expected
In a webdynpro component the data
is linked to the screen elements through the context.Every controller
has its context, and data shared between more than one view should be
put in the componentcontroller context.
In the global context I define a node PARMS with an attribute for every field in SE16_PARMS.
The next step is to use method WDDOINIT to bind attribute SE16_PARMS to the context:
method wddoinit .
data:parms type ref to if_wd_context_node.
*set up the message manager
wd_assist->do_init( wd_this ).
wd_this->se16_parms-tabname = ‘SFLIGHT’.
wd_this->se16_parms-maxrec = 500.
wd_this->se16_parms-keysonly = abap_false.
wd_this->se16_parms-tabdesc = ”.
*Bind the context
parms = wd_context->get_child_node( name = wd_this->wdctx_parms ).
parms->bind_element( new_item = wd_this->se16_parms set_initial_elements = abap_false ).
wd_this->parmsel = parms->get_element( ).
“This will dump if the error occurred creating the message manager
wd_assist->report_error( ‘E01’ ).
As you can see from the code, I also initialize the message
manager I added to the helper class and then use it to report an error.
Table selector view<br />First
of all we copy and bind the context of the view with the global one. To
do so I simply open the context tab, drag node PARMS from the global
context to the local one and answer yes to the box below:
it’s time to actually draw the view, so I move to the layout tab and I
start dragging visual components in the screen area.Not much to say
here, the only interesting stuff is the tabname inputfield, with its
value property bound to TABNAME context element, and the execute
button’s action code, the other stuff is only there to improve the view
layout.Here you can see the layout tree and the properties of the
Here you can see the action method of the execute button, which is mostly a wrapper around a componentcontroller’s method:
method onactionexecute .
wd_assist->report_error( ‘E02’ ).
Anyway it shows how to fire an outbound plug and how I use the helper class to display error messages.
Using webdynpro components
For the next view (SELSCR) I need to use another webdynpro component, WDR_SELECT_OPTIONS.
so requires several tasks in different part of the application, the
first being to add it to the ‘Used components’ tab of the ZSE16_URB
component. I also add the SALV_WD_TABLE,needed in the last view.
Selection screen view
First of all, I go to the properties tab and use the create button to add references to the component I just added:
not done with this guy yet: as we’ll see it also needs some coding, a
VIEW_CONTAINER_UIELEMENT in this view and a setting in the window
structure to specify which component has to be embedded there.
I move to the view layout and design the screen.Some caption texts are
bound to context elements to display table name and description. The
last item we need is a VIEW_CONTAINER_UIELEMENT to put our select
options in.The layout looks like this:
later I’ll move to the main window to embed the actual selection screen in this view container.
define two attributes for this view: SEL_HANDLER, a reference to
IF_WD_SELECT_OPTIONS used to create and manipulating the dynamic select
options, and OLDTABNAME, of type TABNAME, used to check wether we
should rebuild our select-options or not.
In the initialization method I’ll take care of initializing the component usage SEL_HANDLER:
method wddoinit .
data: l_ref_cmp_usage type ref to if_wd_component_usage,
seoptif type ref to iwci_wdr_select_options.
*initialize component usage
l_ref_cmp_usage = wd_this->wd_cpuse_select_options( ).
if l_ref_cmp_usage->has_active_component( ) is initial.
*initialize a handler for select-options
seoptif = wd_this->wd_cpifc_select_options( ).
wd_this->sel_handler = seoptif->init_selection_screen( ).
* init the select screen (hide a few buttons)
wd_this->sel_handler->set_global_options( i_display_btn_cancel = abap_false
i_display_btn_check = abap_false
i_display_btn_reset = abap_false
i_display_btn_execute = abap_false ).
I should have added a little error handling here, but I was too lazy.
The only other significative methods are
HANDLEFROM_TABSEL and ONACTIONRUNQUERY, but they are only tiny wrappers for a few component controller methods described below.
Component controller methods for select-options handling
the method below the only code of some interest on a webdynpro
perspective is the calls to the handler (a reference to
IF_WD_SELECT_OPTIONS) to clean and create the select options
dynamically.If the table hasn’t changed since the last time I ran this
method, no action is taken.
method create_selopts .
data: field type dfies,
rangetab type ref to data,
ftype type string,
fname type string..
* If the last generated select options was for the same table there’s nothing to do
if wd_this->core->tabname = oldtab.
*loop to generate the select options
loop at wd_this->core->userfields into field.
ftype = field-rollname.
fname = field-fieldname.
rangetab = handler->create_range_table( i_typename = ftype ).
handler->add_selection_field( i_id = fname it_result = rangetab ).
oldtab = wd_this->core->tabname.
The other interesting method handles the select options to the
core class to generate a dynamic query and store its result for the
method run_query .
data: sel_fields type if_wd_select_options=>tt_selection_screen_item,
sel_field type if_wd_select_options=>t_selection_screen_item.
wd_this->parmsel->get_static_attributes( importing static_attributes = wd_this->se16_parms ).
handler->get_selection_fields( importing et_fields = sel_fields ).
loop at sel_fields into sel_field.
wd_this->core->add_sel( id = sel_field-m_id rangetab = sel_field-mt_range_table ).
wd_this->core->exec_query( wd_this->se16_parms-maxrec ).
List view<br />This view looks very much like the
selection screen, but has SALV_WD_TABLE as a component usage in place
of WDR_SELECT_OPTIONS and a component ALV_IF which is a reference to
IWCI_SALV_WD_TABLE.<br /><div id=”fk2j” style=”padding: 1em 0pt; text-align: left”>!https://weblogs.sdn.sap.com/weblogs/images/251709722/File_002.png|alt=image|src=https://weblogs.sdn.sap.com/weblogs/images/251709722/File_002.png|border=0!<br /><br />To
complete the work I’ll have to edit the main window to embed the actual
ALV table screen in this view container, as shown below.<br /><br />Most of
the work for getting the ALV list on screen is handled by the following
method (I think the code has enough comments to tell you what’s going
on).For once doesn’t simply rely on the componentcontroller because it
has more to do with screen output that base logic, so I felt this was
the right place for this job.<br /><br />
method handlein .<br />
data: root type ref to if_wd_context_node_info,<br />
dyn_node type ref to if_wd_context_node,<br />
tab type ref to data,<br />
nodename type string.<br />
field-symbols:<tab> type table.<br />
root = wd_context->get_node_info( ).<br />
nodename = wd_comp_controller->get_tabname( ).<br />
*create dynamic context node<br />
parent_info = root<br />
node_name = nodename<br />
structure_name = nodename<br />
is_multiple = abap_true ).<br />
dyn_node = wd_context->get_child_node( name = nodename ).<br />
* Retrieve data and put it into the dynamic context<br />
tab = wd_comp_controller->get_table( ).<br />
assign tab->* to <tab>.<br />
dyn_node->bind_table( <tab> ).<br />
*Link the dynamic node to the ALV component<br />
wd_this->alv_if->set_data( r_node_data = dyn_node ).<br />
catch cx_root.<br />
wd_assist->report_error( ‘E05’ ).<br />
endmethod.<br /><br />Complete window structure
but not least we have to embed the used components views into the view
containers. To do so I go to the main window structure and expand the
tree since I find the VIEW_CONTAINER_UIELEMENT items, then I select
‘Embed view’ from their context menu.In the last picture you can see
both the final window structure and the parameters I used to get it.