Skip to end of metadata
Go to start of metadata

Applies To:

SAP CRM WEB UI Framework version CRM2007 and CRM7.0

Summary:

We may sometime come across a requirement of creating new table views in CRM web UI. This article explains how to create custom table view and integrate it with existing entity like Activity, Campaign etc.  in CRM.

For Bol/Genil part, please refer to my previous blog on simple object :   Simple Object Creation - Bol/Genil Part

If you have successfully tested simple object in genil_bol_browser, then this wiki provide detail step of creating a table view based on that simple object.

Author:  


Company:  Robert Bosch, India   

Created on:    15.12.2010

Author(s) Bio
Sumit has around  5 years experience in CRM domain and have worked extensively on SAP CRM 2007 and 7.0.  His areas of experties include SAP CRM 2007 & CRM7.0 WEB UI Customizations and developments using BOL-GENIL programming, ABAP, OOABAP & BSP programming. 

Development Steps:

Consider a scenario if we need to add Order details in campaign overview page( Campaign(1...n)Order ), to realize this requirement custom order table view is needed which will be integrated in campaign ov_page.

1. Let's Start with creating new view "OrderDetail" under "CPG_MAIN" bsp component. 

2. Specify Context node name "Order" and Bol entity as the simple object created from the previous blog "zorderso". 

3. Click next till last step, in the last screen select view type as "table view", tick the configurable and change/display check boxes.

4. Declare these attributes in the attribute section of the OrderDetail view's implementation class.

5. Modify the code of "OrderDetail.htm" page code with the below code..

OrderDetail.htm
<%@page language="abap" %>
<%@extension name="thtmlb" prefix="thtmlb" %>
<%@extension name="chtmlb" prefix="chtmlb" %>
<%@extension name="bsp" prefix="bsp" %>

<%
data lv_xml type string.
lv_xml =  controller->configuration_descr->get_config_data( ).
%>

<thtmlb:areaFrameSetter toolbarButtons = "<%= controller->tb_button %>"
                        maxButtonNumber = "2"
                        displayMode           = "<%= controller->view_group_context->is_view_in_display_mode( controller ) %>"
                        />

<chtmlb:tableExtension tableId = "Table1"
                        layout  = "FIXED" >
<chtmlb:configTable xml                   =  "<%= lv_xml %>"
                    id                    = "Table1"
                    navigationMode        = "BYPAGE"
                    onRowSelection        = "select"
                    table                 = "//Order/Table"
                    width                 = "100%"
                    displayMode           = "<%= controller->view_group_context->is_view_in_display_mode( controller ) %>"
                    headerVisible         = "FALSE"
                    hasLeadSelection      = "TRUE"
                    usage                 = 'ASSIGNMENTBLOCK'
                    personalizable        = "FALSE"
                    actions               = "<%= controller->gt_button %>"
                    allRowsEditable       = 'TRUE'
                    downloadToExcel       = "FALSE"
                    visibleFirstRow       = "<%= Order->VISIBLE_FIRST_ROW_INDEX %>"
                    selectionMode         = "<%= Order->SELECTION_MODE %>"
                    selectedRowIndex      = "<%= Order->SELECTED_INDEX %>"
                    selectedRowIndexTable = "<%= Order->SELECTION_TAB %>"
                    />
</chtmlb:tableExtension>

6. Click on Configuration tab of  "OrderDetail" view move required field to be shown on the right side under displayed field.

7. Define three buttons Create,Delete,Edit List in do_prepare_output method of the implementation class.

DO_PREPARE_OUTPUT
METHOD do_prepare_output.

  DATA:  ls_button    TYPE crmt_thtmlb_button.
  DATA : lr_entity    TYPE REF TO cl_crm_bol_entity,
         lv_locked    TYPE char1,
         lv_enabled   TYPE crmt_boolean VALUE abap_true,
         lr_coll      TYPE REF TO if_bol_bo_col,
         lv_coll_size TYPE sytabix,
         lv_display   TYPE boolean.

  lv_display = me->view_group_context->is_view_in_display_mode( me ).

  IF lv_display EQ abap_true.
    typed_context->order->set_selection_mode( iv_selection_mode = cl_bsp_wd_context_node_tv=>selmode_none ).
  ELSE.
    typed_context->order->set_selection_mode( iv_selection_mode = cl_bsp_wd_context_node_tv=>selmode_lineedit ).
  ENDIF.

  CALL METHOD super->do_prepare_output.

  lr_coll =   me->typed_context->order->collection_wrapper->get_marked( ).
  IF lr_coll IS BOUND.
    lv_coll_size = lr_coll->size( ).
    IF lv_coll_size = 0.
      lv_enabled = abap_false.
    ELSE.
      lv_enabled = abap_true.
    ENDIF.
  ENDIF.
  CLEAR : tb_button, ls_button.
  ls_button-text     = 'Edit List'.
  ls_button-on_click = 'EDIT'.                              "#EC NOTEXT
  ls_button-enabled  = me->view_group_context->is_view_in_display_mode( me ).
  APPEND ls_button TO tb_button.

  CLEAR gt_button.
  ls_button-text     = 'Insert'.
  ls_button-on_click = 'CREATE'.                            "#EC NOTEXT
  ls_button-enabled  = abap_true.
  APPEND ls_button TO gt_button.
  CLEAR ls_button.

  ls_button-type     = cl_thtmlb_util=>gc_icon_delete.
  ls_button-on_click = 'DELETE'.                            "#EC NOTEXT
  ls_button-enabled  = lv_enabled.
  APPEND ls_button TO gt_button.
  CLEAR ls_button.
ENDMETHOD.

Create three event's "CREATE","DELETE","EDIT" in "OrderDetail" view via wizard.

As there is no direct bol relation between the simple object table node and campaign, to form relationship guid of the campaign is stored in ref_guid field of simple object..this campaign guid(ref_guid) is again used in on_new_focus to retrieve the related order's of a campaign. 

EH_ONCREATE
METHOD eh_oncreate.
  DATA : lr_entity TYPE REF TO cl_crm_bol_entity,
         lv_collection TYPE REF TO if_bol_bo_col,
         lr_comp type REF TO ZL_CPG_MAIN_BSPWDCOMPONEN_IMPL.

  DATA : lr_core     TYPE REF TO cl_crm_bol_core,
         lr_fac      TYPE REF TO cl_crm_bol_entity_factory,
         lt_params   TYPE        crmt_name_value_pair_tab,
         ls_params   TYPE        crmt_name_value_pair,
         lr_ent      TYPE REF TO cl_crm_bol_entity,
         lv_cmp_guid  TYPE        crmt_object_guid.

  lr_comp ?= me->comp_controller.
  Check lr_comp is BOUND.
  lr_entity ?= lr_comp->typed_context->campaign->collection_wrapper->get_current( ).
 "Reading the Campaign entity, which is bound to component controller's
  campaign context node.
  me->typed_context->order->deselect_all( ).

  IF lr_entity->is_changeable( ) = abap_true.
    lr_core = cl_crm_bol_core=>get_instance( ).
    lr_fac = lr_core->get_entity_factory( 'zorderso' ).
    lt_params = lr_fac->get_parameter_table( ).
    TRY.
        lr_ent = lr_fac->create( lt_params ).
        IF lr_ent IS BOUND.
          CHECK lr_ent->lock( ) = abap_true.
          lr_entity->get_property_as_value( EXPORTING iv_attr_name = 'GUID'
                                            IMPORTING ev_result = lv_cmp_guid )."Keeping parent entity "campaign" guid
          lr_ent->set_property( iv_attr_name = 'REF_GUID'
                                iv_value = lv_cmp_guid ).

          me->typed_context->order->collection_wrapper->add( iv_entity = lr_ent ).
          me->typed_context->order->visible_first_row_index = me->typed_context->order->collection_wrapper->size( ).

        ENDIF.
      CATCH cx_crm_genil_model_error.
        EXIT.
      CATCH cx_sy_ref_is_initial.
    ENDTRY.
  ENDIF.
ENDMETHOD.
EH_ONDELETE
METHOD eh_ondelete.
  DATA :  lr_entity TYPE REF TO cl_crm_bol_entity,
          lr_current TYPE REF TO if_bol_bo_property_access,
          lr_col TYPE REF TO if_bol_bo_col,
          lr_core TYPE REF TO cl_crm_bol_core,
          lv_size TYPE i.

  lr_col ?= typed_context->order->collection_wrapper->get_marked( ).
  lv_size = lr_col->size( ).
  IF lv_size > 0.
    DO lv_size TIMES.
      IF sy-index = 1.
        lr_current = lr_col->get_first( ).
      ELSE.
        lr_current = lr_col->get_next( ).
      ENDIF.
      lr_entity ?= lr_current.
      typed_context->order->collection_wrapper->remove( lr_current ).
      lr_entity->delete( ).
    ENDDO.
    lr_core = cl_crm_bol_core=>get_instance( ).
    lr_core->modify( ).
    typed_context->order->deselect_all( ).

  ENDIF.
ENDMETHOD.
EH_ONEDIT
METHOD eh_onedit.
  DATA:    lr_tx           TYPE REF TO if_bol_transaction_context,
           lr_entity       TYPE REF TO cl_crm_bol_entity,
           lr_comp type REF TO ZL_CPG_MAIN_BSPWDCOMPONEN_IMPL.

  lr_comp ?= me->comp_controller.
  Check lr_comp is BOUND.
  lr_entity ?= lr_comp->typed_context->campaign->collection_wrapper->get_current( ).
  CHECK lr_entity IS BOUND.
  IF lr_entity->lock( ) = abap_true.
    me->view_group_context->set_view_editable( me ).
  ENDIF.

  lr_entity ?= me->typed_context->order->collection_wrapper->get_first( ).
  WHILE lr_entity IS BOUND.
    lr_entity->lock( ).
    lr_entity ?= me->typed_context->order->collection_wrapper->get_next( ).
  ENDWHILE.

ENDMETHOD.

8. Create On_new_focus method in the "Order" context node, specify it as a event handler for collection wrapper new_focus event. 

Copy event parameter.


Set handler in Connect nodes method of the CTXT class.

Connect_Nodes
method CONNECT_NODES.

    DATA: coll_wrapper TYPE REF TO cl_bsp_wd_collection_wrapper.
    coll_wrapper = campaign->get_collection_wrapper( ).
    set HANDLER me->order->on_new_focus for coll_wrapper ACTIVATION iv_activate.

endmethod.


As Save event is handled in different view, order data has to be bind to custom/component controller to access it in other views.

  Create "Order" context node in custom/component controller and perform the binding as shown below.  For this scenario "Order" context node is bound to campaign component controller     "Order" context node, in CRM 7.0 it can be done through wizard via creating binding option.

CREATE_ORDER
method CREATE_ORDER.

    DATA:
      model        TYPE REF TO if_bsp_model,
      coll_wrapper TYPE REF TO cl_bsp_wd_collection_wrapper,
      entity       TYPE REF TO cl_crm_bol_entity,           "#EC *
      entity_col   TYPE REF TO if_bol_entity_col.           "#EC *

    model = owner->create_model(

        class_name     = 'ZL_ZCPG_MAI_ORDERDETAIL_CN00'

        model_id       = 'Order' ).                         "#EC NOTEXT
    Order ?= model.
    CLEAR model.


      owner->do_context_node_binding( iv_controller_type  = cl_bsp_wd_controller=>co_type_component
                                  "iv_name             = 'CPG_MAIN/BSPWDComponent'         "#EC NOTEXT
                                  iv_target_node_name = 'Order'
                                  iv_node_2_bind      = Order ).


* Added by wizard
* bind Context Node to controller
    coll_wrapper =
      campaign->get_collection_wrapper( ).
    TRY.
        entity ?= coll_wrapper->get_current( ).
      CATCH cx_sy_move_cast_error.
    ENDTRY.
    IF entity IS BOUND.
      Order->on_new_focus(
                   focus_bo = entity ).
    ENDIF.

endmethod.

   Redefine eh_onsave event of the save method in "CPG_MAIN/OPOverview" component/view.

EH_ONSAVE
EH_ONSAVE.

CHECK check_before_save( ) IS INITIAL.

  DATA  rv_success    TYPE        abap_bool.
  DATA  lr_tx_manager TYPE REF TO cl_mktprj_transaction_mgr.
  DATA: lv_success    TYPE abap_bool.


  DATA: my_tx_context  TYPE REF TO cl_crm_bol_custom_tx_ctxt,
        lr_coll_wr TYPE REF TO cl_bsp_wd_collection_wrapper,
        lr_tx_ctxt      TYPE REF TO if_bol_transaction_context,
        lr_entity_so  TYPE REF TO cl_crm_bol_entity,
        lr_coco TYPE REF TO zl_cpg_main_bspwdcomponen_impl.

  CREATE OBJECT my_tx_context.
  lr_tx_manager = cl_mktprj_transaction_mgr=>get_instance( ).
  my_tx_context->add_tx_context( lr_tx_manager ).

  lr_coco ?= me->comp_controller.
  IF lr_coco IS BOUND.
    lr_entity_so ?= lr_coco->ztyped_context->order->collection_wrapper->get_current( ).
    IF lr_entity_so IS BOUND.
      lr_tx_ctxt = lr_entity_so->get_transaction( ).
      my_tx_context->add_tx_context( lr_tx_ctxt ).
    ENDIF.
  ENDIF.
  rv_success = lr_tx_manager->save_all( ).
  IF lr_entity_so IS BOUND.
    my_tx_context->if_bol_transaction_context~save( ).
    my_tx_context->if_bol_transaction_context~commit( ).
  ENDIF.
  IF rv_success = abap_true AND me->view_group_context IS NOT INITIAL.
    eh_oncancel( ).
  ENDIF.
 lr_cmp->typed_context->campaign->collection_wrapper->publish_current( ).

ENDMETHOD.

   Add the following code in on_new_focus method, here logic is to retrieve the order entities collection related to  campaign only if parent entity "campaign" changes..

ON_NEW_FOCUS
METHOD ON_NEW_FOCUS.

    DATA:   entity        TYPE REF TO cl_crm_bol_entity,
            lr_old        TYPE REF TO cl_crm_bol_entity,
            query         TYPE REF TO cl_crm_bol_query_service,
            result        TYPE REF TO if_bol_bo_col,
            lv_old_guid   TYPE        crmt_object_guid,
            lv_guid       TYPE        crmt_object_guid.

    entity ?= focus_bo. " Campaign entity
    CHECK entity is BOUND.
    entity->get_property_as_value( EXPORTING iv_attr_name = 'GUID'
                                            IMPORTING ev_result = lv_guid ).
    lr_old ?= me->collection_wrapper->get_current( ).
    if lr_old is BOUND.
      lr_old->get_property_as_value( EXPORTING iv_attr_name = 'REF_GUID'
                                     IMPORTING ev_result = lv_old_guid ).
    ENDIF.
* Fire Query only if campaign entity is changed    "lv_old_guid - Order Entity guid "lv_guid - campaign guid
    if lv_guid ne lv_old_guid.
          query = cl_crm_bol_query_service=>get_instance( 'zso_ordersearch' ).
          query->set_property( iv_attr_name = 'REF_GUID'
                               iv_value = lv_guid ).
          result ?= query->get_query_result(  ).

    me->set_collection( result ).
    ENDIF.

ENDMETHOD.

9 . Add the OrderDetail view to runtime repository..

10. Expose "OrderDetail" view on Campaign Overview page, maintain view title and save. 

Now run the application campaign overview will have order details table view as an assignment block.

12 Comments

  1. Unknown User (czjxhbn)

    Hi Sumit,

    Thanks for sharing this.

    May I ask if you know how we can add a new attribute to an existing view ? example a new attribute - Volume to the existing Competitor Product view in Corporate Account (component BP_DATA/CorpAccountCompProdOV)

    Thanks & Rgds,

    Josephine



  2. Hi Sumit,

    As you mentioned in the first step :

     1 Let's Start with creating new view "OrderDetail" under "CPG_MAIN" bsp component

    How did you get the wizard for creating the view as mentioned in:

    Thanks

    Ricky

  3. Hi Ricky :

    I hope you are asking about "create new view wizard": here is the detail..

    Open the bsp component( trxn BSP_WD_CMPWB) with enhancement set , you should be able to see component structure browser on the left hand side, navigate to "views" under components  right click and choose "create" this will open wizard for creating new views.

    Let me know if it doesn't answer your query.

    Cheers,

    Sumit

  4. Hi Josephine,

    For creating new attributes in an existing views this wiki won't help much.. you can probably try for AET provided the object is supported via extensibility tool or you can add it via append strucuture or some other approach.

    Cheers,
    Sumit

  5. Unknown User (106ex4scs)

    Hi Sumit,

    I am doing a very similar implementation (Simple Object content to be shown in table view in CRM Webclient). I am facing a peculiar problem.

    My parent context node is BTAdminH (Instead of Campaign in the above blog) and my Simple Object is related to Competitor.

    Since Initially, the competitior table is empty at the database level, the result of the view is that it shows 'No Result Found' literal in the content of the table (Instead of showing normal rows in the table). Subsequently, when I press EDIT LIST, the buttons Insert and Delete begin to appear. Also I can see a row being added to the table, but this row is not editable, I mean I cannot add any content in the row of the table.

    Could you help me. Am I right in expecting the row content to be editable and when I press Insert, the program should read the row content and create simple object and subsequently fill up the z-table related to Simple Object.

    Your Help and guidance will be very valuable.

    Regards

    Tushar

  6. Former Member

    Hello,

    in case you can' find your Z bol entity when creating the view (step 2) you have to change the model to ALL in the Runtime Repository Editor.
    Regards, Roman

  7. Unknown User (j96p3yx)

    Hi,

    Excellent doucment. Thanks a lot

  8. Unknown User (a9ccno2)

    Hi Sumit,

    Thanks for this nice document.

    I have a requirement where i need to display a Z table data in a New Assignment block in a Campaign.

    The Z table has Campaign ID as key field and another 3 fields. The user should be able to Create/Edit/Delete the entries from the Assignment block.

     http://wiki.sdn.sap.com/wiki/display/CRM/CRM+Web+UI+Technical+-+Creating+Table+View+In+Web+UI?focusedCommentId=281774446&#comment-281774446

    So, can i follow the above approach which you have given ?

    And one more thing... when i click on your previous blog "Simple Object Creation - Bol/Genil Part" it doesn't open. I think the hyperlink to your previous blog is not working.

    Can you provide me the link for your previous blog "Simple Object Creation - Bol/Genil Part".

    And if we just create simple object and follow the steps given in this blog then is it enough to display/Create/Edit/Delete entries in the New Assignment block in Campaign

    or do we also need to maintain some entries in T code CRMC_MKTIB_IL_CUSTOM for Application CRMD_MKTPL Node Name MKT_CAMPAIGN?

    =====Hi, i have another question. I have created a custom BOL object referring to my Z table. Now I want to create a view which will display along with the Campaign details. But now i am confused whether to create the New Assignment block in the CPGOE_DETAILS component or CPG_MAIN component OR CPGOE_ABLOCKS Component ?

    The current Campaign Header details view is from the component CPGOE_DETAILS component. and rest of the assignment blocks like segments, Campaign Elements are from CPGOE_ABLOCKS. So, can you guide me in which component i should create this New Assignment block ?

    Regards,

    Chetan

    Please suggest.

    Thanks In Advance for your quick response.

    Reg,

    Chetan

  9. Thanks, Sumit!

    I made some enhancment on Change Request Management in Solution Manager based on your blog's hint.

    Really helps a lot.

  10. I have added the same way as table assignment block  along with Delete button. When I click on Delete button, it is directly deleting that record from data base .

    It is reverting  that record into table AB even though I click on Cancel in overview page . 

    Yes, it is old wiki.  dont know whether I am going get reply from sumit or not. If anybody please let me know.

    Regards,ram

     

    1. Former Member

      Hi Ram Ram,

      I facing the same issue as you were.
      The record gets deleted from the data base as soon as Delete button of Assignment Block is clicked. Were you able to solve it and how ??

       

      Regards,
      ND 

  11. Former Member

    Hi Hi Ram Ram,

    Thanks for the Nice blog  How can I create table view on same window of account identification view.?

     

    Regards

    Hulisani

     

    .