Applies to:
SAP CRM WEB UI Framework version CRM2007 and CRM7.0
Summary
This article explains about a technique that can read/modify one context node attributes from some other context node attribute's methods like GETTER-SETTER methods or any other method of context node class (i.e. CNxx class). The beauty of this technique is no need to code in Controller class ( IMPL class) .
Author(s):
Company: Q2Con ApS, Copenhagen, Denmark
Created on: 29.09.2010
Author(s) Bio
Suchita has been working in SAP CRM domain from 5+ years and have worked on almost all SAP CRM versions from 4.0 till 7.0 including CRM2007 with Innovative and Extremely quality conscious approach and a great eye for analytical details. She is experienced on several SAP CRM Implementation projects globally & also have been awarded for some of her project executions. Her areas of experties include SAP CRM 2007 & CRM7.0 WEB UI Customizations and developments using BOL-GENIL programming, ABAP, OOABAP & BSP programming.
Conventional Approach for data exchange between different context node:
One common requirement in WEB UI is to exchange the data between different context nodes of a view.
We generally need to exchange the data (basically attribute values) in situations where value of one context node attribute depends on the other context node attribute. I have often found that technical consultants achieve this in View Controller class - IMPL class because it has access to all context nodes through TYPED_CONTEXT attribute. Following is a sample code that illustrates this approach :
Here we are required to set some attribute, say ATTR2 (Dependent) of Context node B by evaluating some condition on an attribute, say ATTR1 (Dependable), of context node A.
The conventional approach is
1) Read Dependable attribute, ATTR1 .
2) Put its value in a temporary holder, say ZTEMP attribute of Context Node B
3) In getter-setter of Dependent attribute, ATTR2 ,use the ZTEMP which reflect value of ATTR1.
ZTEMP is a must in this approach to act as a Flag because ATTR1 and ATTR2 can not share their data directly as they belong to different context node and thus not accessible in their respective context node classes.
Write code in IMPL class for steps 1) and 2) because IMPL can access context node A and B both.
lv_entityA ?= me->typed_context->node A->collection_wrapper->get_current( ). lv_value = lv_entityA~if_bol_bo_property_access->get_property_as_srting( 'ATTR1' ) . If <some condition> lr_entityB ?= me->typed_context->node B->colloction_wrapper->get_current( ) . lv_entityB~if_bol_bo_property_access->set_property( name = 'ZTEMP' Value = lv_value ). Endif.
then write code in Context node B class (CNxx), typically in GET_ATTR2 method, to set the ATTR2 from ATTR1 via this Z attribute.
There is no harm in this approach and I would like to share this thread where the guy struggled so much to read one context node attribute in other context node and finally above said approach came to his rescue.
I, myself, have used this same long approach previously in my work and then one day it made me think, why code in IMPL class? Just because it has access to all context nodes via CTXT class instance called typed context ? And if so, then why not have a CTXT class instance itself in my context node class ? Then I can easily read all context nodes.
As we all know, all the context nodes are attributes of view's context class, i.e. the class ending with _CTXT. Now the View controller class, i.e. the one ending with IMPL, has a public attribute typed_context TYPE CL______CTXT.Hence, in controller class, i.e. IMPL class, you can access any context node as
me->typed context->context node name.
The New Approach:
Now imagine, if you can get the instance of CTXT class in a context node class itself (i.e. the class ending with CNxx e.g. CN00, CN01 etc.)? Then you can access all other context nodes through this instance. Not only that you can access other context node's attributes just to read but you can also use set properties, get properties to set/reset attributes too. Sounds great right ?? sounds simple too and trust me it's really simple to implement this and we are going to do that next.
Illustration on the New Technique:
Let's take an as example, very close to above mentioned thread .
Component/View = BP_ADDR/ Standard Address
view StandardAddress has two context nodes. 1) Header 2) StandardAddress.
Requirement: - 'HEADER' has an attribute which needs to be processed depending upon the value of attribute "Country" of node 'STANDARDADDRESS'. Let's, for example, we need to set NAME4 attribute of HEADER as say RESIDENT OF by reading COUNTRY attribute of STANDARDADDRESS node. Thus if country field of standard address node has value as DK then in NAME4 field we will put value as Denmark Resident .This is just a condition for sake of illustration.
Since we need to read context node STANDARDADDRESS's attribute 'country' in context node HEADER, let's begin coding in context node HEADER class. (I assume that you have enhanced the component and the view and the context nodes)When you open CTXT class and look into Tab Attributes, you will find that the context node you enhanced, system added one more context node same as the enhanced node but in Z namespace and private scope. So when you enhanced context node HEADER, system must have created a replica of this header node as ZHEADER in CTXT class with scope as Private. We need to change the scope to "Protected" as shown in the pic. below
step 1) In the context node class of node HEADER, Create an attribute of the context class (CTXT class).
GR_OWNER Instance Attribute Public Type Ref To CL_XX_XX_XXXX_CTXT (give the name of Context class)
step 2) Now in the view context class (CTXT class) there will be a method CREATE_HEADER( ). Write following code in this method as shown in the pic. You just need to add the highlighted code lines shown in the image below. Let rest of the code remain as it is as generated by system.
Step 3) Now in the context node class, you can access any other context node as you have the instance to CTXT class with you and CTXT class has all context nodes as its attributes. So you can get the other context node entity as follows:
DATA lr_entity type ref to cl_crm_bol_entity . CHECK gr_owner IS BOUND." get the current entity of other context node lr_entity ?= gr_owner->OtherContextNodeName->collection_wrapper ->get_current( ). CHECK lr_entity IS BOUND. " read the property of other context node Lr_entity->if_bol_bo_property_access~get_property( iv_atrribute = 'AN ATTRIBUTE' EXPORTING value = lv_value )
The image below illustrated the code in GET_NAME4 method of context node HEADER.
As you can see, now using gr_owner attribute, we can access the other context node and can call its GETTER_SETTER for any of its attributes.
Now add the NAME4 field on the View using config tool. Also we keep it as display only by ticking the checkbox for display only in view config tool.
Find below the result as appeared on Web UI after we added the NAME4 attribute of HEADER on the view and copied the country_text attribute from node STANDARDADDRESS into it.
As you can see, the Name4 field has the value Denmark, which is as read from the context node STANDARDADDRESS attribute "country_text".
Related Content
Reference 1- Refer following thread on SDN which gave me an inspiration to blog/wiki on this technique:
14 Comments
Pravin Pattewar
Very Innovative Idea !! Thanks ..
I used this concept for passing View controller reference from context node class to the tree proxy classes below the hierarchy.
Tree proxy classes do not have any refernce to view controller (IMPL) class but for some requirement it was needed to check IMPL class at that level. Context node class has view controller reference (IMPL class) in its attribute 'GR_OWNER', which is passed to child tree proxy class in 'Refresh' method.
Unknown User (d3jfzqo)
Hi suchita,
Thank you for such a wonderful blog.
I have a doubt
In this case you have taken 2 fields of the same component. In my requiremnt,
In appointment page, i need to populate the account name and his address(which is stored in account page) in location field. Could you guide me the method for this?? What are the changes that i should make??? It would be of great help.
REGARDS
CHANDRAKANT KULKARNI
Sandesh K
Thank you. That is a wonderful article.
Former Member
Hi,
I am working as ABAP Developer. I just begin to learn CRM Wb UI Technical. Can any one suggest good material or video tutorials for beginners.
Unknown User (shhe5d5)
Hello Suchita... No doubt.. it is a nice blog and you've explained in very detailed. Appreciate your interest and efforts in sharing knowledge.
Can we able to delete a custom context node which has been created by extending a standard component view ? As I don't the delete option in IDES but not sure about the same in CRM 7.0 EHP1. Appreciate your earliest response.
Thanks,
Unknown User (100j4txc2)
Hi All,
In Corporate Account creation in WEB UI. I want add a view below the marketing attributes.
I went to BP_DATA component , i have added Z view . I have assigned the Z view to the window (Window BP_DATA/MarketingAttributesEOVPList) where the Marketing attribute view (BP_DATA/MarketingAttributesEOVP) is assigned.
But my Z view is not vailable in Corporate Account creation in WEB UI.
Pls assist me, where is the problem.
Thanks,
Kishan
Ashokkumar Mohan
Hello Suchita,
Thanks a lot for ur valuable contribution..As a beginner it is very useful for me..
Thanks
Ashokkumar.
Former Member
Wow!!! this is really amazing.. Thnx Suchita for a wonderful blog.
Regards,
Raja Sekhar K
Former Member
Hi Suchita,
I used it for two applications (1. copying the Reason code to Description in Interaction Record creation and 2. defaulting a check-box field (custom field added) in Service Request based on some field value in BP).
It was working fine for 1st case. For 2nd case the defaulting is working fine but the values are not getting updated in SAP Data Base tables. Any idea why this can happen? I am getting cx_crm_cic_parameter_error error at the statement "dref = current->get_property( 'ZZFLD000006' ). "#EC NOTEXT" of Set and Get methods.
Any inputs on this will be greatly appreciated.
Regards,
Raja Sekhar K
Ruslan Strelnikov
Hi Suchita,
I think it's not good idea.If I understood you want to get access from getters of one context node to values from another. But if the last context node is not created or not updated? May be better to use DO_PREPARE_OUTPUT of the view. From it you can get values of all context nodes....
Regards,
Ruslan
Former Member
Thank you, helped a lot
David Fryda
Hi,
I am following the conventional approach described at the the top of this document.
I am working in component SRQM_INCIDENT_H/IncidentHeaderEF.
I created a method in IMPL class called do_test. I need to read BTPARTNERSET node and retrieve the REPORTER attribute.
I am getting a null exception with the following code:
DATA: lv_entitya TYPE REF TO cl_crm_bol_entity,
lv_reporter TYPE string.
lv_entitya ?= me->typed_context->btpartnerset->collection_wrapper->get_current( ).
lv_reporter = lv_entitya->get_property_as_string( iv_attr_name = 'REPORTER' ).
The me->typed_context is INITIAL.
Any help ?
Thank you.
Regards.
Christian Drumm
Hi David,
the question is at what point in time do you call your do_test method. If me->typed_context is initial it seems you call the method before the context was initialized.
As this questions is not directly related to the topic describe don the wiki page I'd suggest asking the question in the WebUI forum.
Christian
David Fryda
Hi Christian,
Thank you.
Regards.