Registration

Dear SAP Community Member,
In order to fully benefit from what the SAP Community has to offer, please register at:
http://scn.sap.com
Thank you,
The SAP Community team.
Skip to end of metadata
Go to start of metadata

Link to Content's target Space :

http://wiki.sdn.sap.com/wiki/display/CRM/CRM+Web+Client+UI+Framework

Applies to:

CRM 6.0/7.0

Summary

Creation of dynamic Component Usages in CRM WebClient UI.

Author(s):  

   Arun Prakash Karuppanan
Company:     Acceture
Created on:    April 17 2010
Author(s) Bio
Arun Prakash Karuppanan is a Software Programmer employed with Accenture, working on CRM implementations.

Table of Contents

Intro

The re-usability of BSP components in the form of a Component Usages is a good thing.We usually depend on static declarations in the runtime repository. However, in certain scenarios, this static declarations may be cumbersome. For example, when you want multiple reuse of the same component and do not know how many until at runtime. In these circumstances, we can dynamically create the component usages. Usually, the data is supplied by the calling component and this happens in the form of context node binding. Don't worry, we can do that as well.

Creating Dynamic Component Usages

Our scenario is multiple reuse of the same component. For binding purposes, we will need a existing context node which will serve as the model type, when creating the context nodes dynamically. The other thing is, all the component usages and context nodes are created dynamically and available only in memory. So, we will need a place where we can store these instances. If we follow a naming convention for the component usages and context nodes, it will make things easier as well. For example, CU_<Used_Component_name>_<Instance_Number> and similarly for context nodes. The storage place can be a table attribute in the component controller class.

       Creating component usages is rather easy.  Create a method in the component controller, that you can call when you need to create them.

METHOD create_component_usage.
 CALL METHOD me->repository->create_cmp_usage_def
  EXPORTING
   iv_usage_name = iv_usage_name
   iv_reference_usage_name = iv_reference_usage_name
   iv_component_name = iv_component_name
  EXCEPTIONS
   duplicate_entry = 1
   OTHERS = 2.
  IF sy-subrc <> 0.
  ENDIF.
ENDMETHOD.

 Parameter iv_usage_name obviously takes in component usage name. We will not be using the second import parameter iv_reference_usage_name. Trying to use this results in a funny behaviour(the view controller gets shared and all of them behave in the same way in UI). However, since it is a mandatory parameter we will pass a blank here. iv_component_name is the component name.

Creating Context Nodes

 Next, we will use an already available method in the component controller class to create context nodes at runtime. Note that you should have already created a context node that will serve as the model type. We will be creating several instances of this at run time.

create_model(
class_name = '<your_context_node_class>' "blueprint class
model_id = <context_node_name> ).

Once you create the  component usage and a context node for binding, you should store the instances in the table attribute in the component controller.

Context node binding

So now, we can create the component usage and the context node as well.  How to do the data binding? Normally, this binding will be specified in the WD_USAGE_INITIALIZE method of the component controller. Note that the method used for binding there will look for statically created context nodes. Instead, we must make it look for the context node among the dynamically created instances. All the created context nodes will be available in the table m_models of the component controller. So, create a method in the component controller which will do the binding that suits our need.

Copy the method  bind_context_nodes in the component controller and modify it as follows.

Note that you can get the  component usage instance by using the method get_component_usage in the component controller. You need to pass the usage name.

METHOD bind_context_nodes2.
DATA: lv_node_2_bind TYPE REF TO cl_bsp_wd_context_node,
      ls_model LIKE LINE OF m_models,
      lv_cnode_name TYPE string.
DATA: lv_target_controller TYPE REF TO cl_bsp_wd_controller,
      lv_target_node TYPE REF TO cl_bsp_wd_context_node.
lv_node_2_bind = ir_usage->if_bsp_wd_component_usage~get_context_node(
                                            iv_node_2_bind ).

CHECK me->do_binding = abap_true.
TRY.
 lv_target_controller = me.
 lv_cnode_name = iv_target_node_name.
 TRANSLATE lv_cnode_name TO LOWER CASE.
 READ TABLE m_models WITH KEY model_id = lv_cnode_name INTO ls_model.
 IF sy-subrc EQ 0.
  lv_target_node ?= ls_model-instance.
 ELSE.
  RAISE EXCEPTION TYPE cx_bsp_wd_incorrect_implement
  EXPORTING
  controller = iv_name.
 ENDIF.
* Share collection wrapper
 lv_node_2_bind->collection_wrapper->attach( lv_target_node->collection_wrapper ).
CATCH cx_sy_move_cast_error cx_sy_ref_is_initial.
 RAISE EXCEPTION TYPE cx_bsp_wd_incorrect_implement.
ENDTRY.
ENDMETHOD. "bind_context_nodes2

Embedding in a view container

So, we have created the component usage and finished with the binding. Now, we must embed them in a view. For our scenario, creating view areas in a view set dynamically is preferable.  We should construct a name for the view area following similar naming conventions used for the usages and context nodes.  A dedicated view controller  should be created for each view area. The code could be put in a suitable method in the view set's controller. The code could be something like

For each component usage instance,

a. construct view area name following naming conventions
b. Create repository view and view area controller

Note: When creating the repository view, the repository view name should be of the format <usage_name>.<interface_view_name>.
For example, if  I have used 'BT115QIT_SLSQ/ItemsList' interface view of the BT115QIT_SLSQ component, the code should be

CONCATENATE <usage_name> 'BT115QIT_SLSQ/ItemsList' INTO lv_view_name SEPARATED BY  '.'  .

Data: lr_rep_view TYPE REF TO cl_bsp_wd_rep_view.

lr_rep_view = rep_view->create_instance_by_name( lv_view_name ).
*Embed the repository view in a new view area
*If the passed view area is not already present, it will be automatically created and a view controller too
      CALL METHOD me->bind_view
        EXPORTING
          rep_view = lr_rep_view
          viewarea = <view_area_name>
         * suppress_area_init = SPACE
        * suppress_area_init_single = SPACE
        * iv_suppress_context_init = ABAP_FALSE
        * iv_force_binding = ABAP_FALSE
       RECEIVING
        controller = lr_controller "your view controller
Note that the view destroying the controllers should be handled diligently.
The controller instances will be present in the table m_subcontrollers of the viewset controller.

 
c. Get the context node name for this component usage from the table in the component controller
	and do the binding using our method

 lr_usage ?= lr_coco->get_component_usage( iv_usage_name =<component_usage_name> ).
CALL METHOD lr_coco->bind_context_nodes2
        EXPORTING
             iv_controller_type = cl_bsp_wd_controller=>co_type_component
            * iv_name =
             iv_target_node_name = <context_node_name>
            iv_node_2_bind = '< context_node_name of used component>'
            ir_usage = lr_usage.

d. In the html view, call the view areas.
<bsp:call comp_id = "<%= controller->GET_VIEWAREA_CONTENT_ID( view_area_name ) %>"
url = "<%= controller->GET_VIEWAREA_CONTENT_URL( view_area_name ) %>"  />




 Note:

        If you wish for a detailed working example, please access this document. I wrote this article, but since it was my first submission, messed up with the category and the name and thus it's been put in a place where it is nearly not as useful.  The article actually focuses on CRM WebClient UI and the BSP component workbench(BSP_WD_CMPWB). I knew that the WD stands for WebDynpro. What I did not know was WebDynpro was a different platform altogether from the BSP Workbench!!! Yes, I was a frog in the well.

http://www.sdn.sap.com/irj/scn/index?rid=/library/uuid/50f7c4b9-fffd-2c10-6d99-c5aacbc0bbb5 

Related Content

Article - Dynamic Component Usages and Context Nodes

Useful Information

Dynamic Component Usage in CRM WebClient UI

2 Comments

  1. Hi Arun,

    I am actually not getting this. Can you tell me while you create a UI Component using AET Table extension that UI comoponent would not be assigned in runtime repository of the parent component's component usage. I think it is using dynamic component usage concept. can i know where sap wrote the code.

  2. Former Member

    Hi Dhruvin,

    Were you able to fix this issue. Even I have a similar requirement. I have created a AET table component for BP. This component is now embedded in BP overview page. When I click the edit link button on AET table, it leads to exception - Define navigation link for the source view " " in BP_HEAD. The source view has a dynamic component usage prefix. I'm not in a position to define the component usage for the Z compoent in BP_HEAD and solve this issue, Any help would highly be appreciated.

     

    Thanks,

    Chakram Govindarajan