Thursday, October 2, 2014

OAF - Personalize Differently!

Was working on Oracle EBS OAF personalization, and wow it is one hack of a framework. For a long time, I thought APEX and ADF had to the bottom of intelligence pyramid, but OAF broke that by million points!

There are tons of restriction on what you can do and not to do with OAF personalization framework, and yeah you can get access to controller and do a lot more as you get access to pageContext and webBean, but there are still tons of limitation. E.g. adding table column with multiple icons in it (not advance table) or adding switcher column on existing table with icons, etc.. Here is another approach which might work better. Integrate it with JQuery and then use JQuery's power to do anything you like on the page. As we all know, with JQuery - sky is the limit!

Here is how we did it :

Step 1 : Upload JQuery to EBS

  • Copy JQuery related files to EBS server ($OA_MEDIA/xx_demo/images):
    • Copy all images which comes with JQuery to
  • Copy all JS files to EBS server ($OA_HTML/xx_demo/js):
    • jquery-1.11.0.min.js
    • jquery-ui-1.10.3.custom.min.js
  • Copy all CSS files to EBS server $OA_HTML/xx_demo/css
    • jquery.ui.all.css (alternatively you can all copy jquery-ui.min.css)
  •  Update CSS files for the image reference. 
    • Search/Replace images/ -> /OA_MEDIA/xx_demo/images/
  •  Create a custom JS file
    • This file will contain all your customization needs to be done.
    • I created xx_demo_oaf_customization.js
    • Copied this file to $OA_HTML/xx_demo/js
    • This file will have function called xx_oaf_customize which will be called when page is fully loaded

Step 2 : Load JQuery on EBS page

This is sensitive piece. There are multiple way to do so, and each one has it's plus/minus:

Option 1 : Modify OAPageBean class
  • Decompile $JAVA_TOP/oracle/apps/fnd/framework/webui/OAPageBean.class
  • Under addJavascriptForNewFeatures function, you can add JQuery libraries as below:
 mPageContext.putJavaScriptLibrary("jqCore", "/OA_HTML/xx_demo/js/jquery-1.11.0.min.js");            
 mPageContext.putJavaScriptLibrary("jqCore", "/OA_HTML/xx_demo/js/jquery-ui-1.10.3.custom.min.js");            
 mPageContext.putJavaScriptLibrary("jqCore", "/OA_HTML/xx_demo/js/xx_demo_oaf_customization.js");            
  • Recompile and put it back, in this case the JQuery will be loaded on all OAF page in system
  • This is probably not very good idea

Option 2 : Customize/Extend the controller

  • Write a controller and extend it. Controller will provide access to webBean and pageContext
  • From page context, we can add JS as below 
 mPageContext.putJavaScriptLibrary("jqCore", "/OA_HTML/xx_demo/js/jquery-1.11.0.min.js");            
 mPageContext.putJavaScriptLibrary("jqCore", "/OA_HTML/xx_demo/js/jquery-ui-1.10.3.custom.min.js");            
 mPageContext.putJavaScriptLibrary("jqCore", "/OA_HTML/xx_demo/js/xx_demo_oaf_customization.js");            
  •  We can attach this controller to a specific page and then JQuery will be loaded on that page

Option 3 : Customize oafcoreR121.js
  • Any OAF page includes $OA_HTML/cabo/oajsLibs/oafcoreR121.js, so I added a few lines of code in oafcoreR121.js to load 
    • JQuery related javascript
    • CSS files and 
    • then call xx_oaf_customize function (in xx_demo_oaf_customization.js file) when page is completely done with loading. 
  • Code I put inside oafcoreR121.js is as below or you can download here:
      /* XX OAF Customization to load JQuery : START */  
      /* generic function load script */  
      /* note: we could certainly use below, but jquery is not yet loaded. */  
      /* loadScript(jsURL, callback); */  
      function xx_loadScript(url, callback) {  
           var head = document.getElementsByTagName('head')[0];  
           var script = document.createElement('script');  
           script.type = 'text/javascript';  
           script.src = url;  
           script.onreadystatechange = callback;  
           script.onload = callback;  
      /* XX load jquery core js */  
      xx_loadScript("/OA_HTML/xx_demo/js/jquery-1.11.0.min.js", xx_jquery_js_loaded);  
      /* XX load jquery UI js */  
      function xx_jquery_js_loaded() {  
           xx_loadScript("/OA_HTML/xx_demo/js/jquery-ui-1.10.3.custom.min.js", xx_jquery_ui_js_loaded);  
      /* XX load oaf customization js */  
      function xx_jquery_ui_js_loaded() {  
           xx_loadScript("/OA_HTML/xx_demo/js/xx_demo_oaf_customization.js", xx_jquery_xx_demo_oaf_customization_js_loaded);  
      /* XX load css, and call entry point */  
      function xx_jquery_xx_demo_oaf_customization_js_loaded() {  
           $("<link/>", { rel: "stylesheet", type: "text/css", href: "/OA_HTML/xx_demo/css/jquery.ui.all.css"}).appendTo("head");  
           $(document).ready(function() {  
      /* XX OAF Customization to load JQuery : END */  

Step 3 : Personalization Begins!
Now you can do anything you would normally do as JQuery guru. For small example, I had a table below in EBS, and I just wanted to add column with multiple rows.

This is how I did inside xx_demo_oaf_customization.js file: - download here.

 function xx_oaf_customize() {  
      if( $("[id$=DefaultFormName]") && $("[id$=DefaultFormName]").attr('action') ) {  
           if( $("[id$=DefaultFormName]").attr('action').indexOf("IcxPorRcvHomePG") > -1 ) {  
                // iProcurment.Receiving Page Found  
                console.log(' Receipt Page Found ' );  
                if( $("[id$=ReceiptsTableRN]") ) {  
                     // Table Region Found  
                     console.log(' ReceiptsTableRN region found ' );  
                     if( $("[id$=ReceiptsTableRN]").find("table.x1h") ) {  
                          console.log(' Table found ' );  
                          $("[id$=ReceiptsTableRN]").find("table.x1h").find("th:last").after("<th class='x1t x4m' scope='col'> <span id='XX_OASH__643' class='x24'>Demo Actions</span></th>");  
                          $("[id$=ReceiptsTableRN]").find("table.x1h").find("tr").each( function() {  
                               if( $(this).find('td') ) {  
                                    $(this).find('td:last').after("<td class='x1p x50'> <a id='XX1:ViewDetailImage:0' href='' onclick='' name='XX1:ViewDetailImage:0'> <img border='0' align='middle' title='View Details' src='/OA_MEDIA/eyeglasses_24x24_transparent.gif'> </a> <a id='XX2:ViewDetailImage:0' href='' onclick='' name='XX2:ViewDetailImage:0'> <img border='0' align='middle' title='View Details' src='/OA_MEDIA/xx_demo/images/details_close.png'> </a> <a id='XX3:ViewDetailImage:0' href='' onclick='' name='XX3:ViewDetailImage:0'> <img border='0' align='middle' title='View Details' src='/OA_MEDIA/xx_demo/images/details_open.png'> </a></td>");  

Now OAF page has the column I need:


Unknown said...

I have followed the steps but problem I am facing is javascript file is not loaded when page is called. As a result javascript error is thrown "Object Expected".

Chintan Shah said...

Which version of EBS are using? I was using 12.1 so EBS was always loading : $OA_HTML/cabo/oajsLibs/oafcoreR121.js In your case, it might be different. You can just use firebug or IE dev tools to see which JS it calls and put your code accordingly.

Venkatn said...

Nice article

How i am using the following code to call page in separate window
String pubOrderId = pageContext.getParameter("orderId");
StringBuffer l_buffer = new StringBuffer();
StringBuffer l_buffer1 = new StringBuffer();
l_buffer.append("javascript:mywin = openWindow(top, '");
String url = "/OA_HTML/OA.jsp?page="+l_buffer1.toString();
OAUrl popupUrl = new OAUrl(url, OAWebBeanConstants.ADD_BREAD_CRUMB_SAVE );
String strUrl = popupUrl.createURL(pageContext);
l_buffer.append("', 'lovWindow', {width:750, height:550},false,'dialog',null);");

Here how can i maintain the focus on child window

Thanks & Rgeards

Chintan Shah said...

I have not tried this myself, so not sure. Is openWindow() your custom javascript function?

Venkatn said...

Hi Chinthan

Thanks I got the Solution
GOt the Solution Form

Thanks & Regards

Karthick said...

I have followed all the steps and i have used Option 2 of extending controller for loading the js files.
How to call the function that was written in xx_demo_oaf_customization.js from controller

Chintan Shah said...

Karthik, it should call xx_oaf_customize automatically after page is loaded. Can you put alert and see if shows up, if not might have to troubleshoot with dev console (e.g. firebug) to see what is going on.

Venkatn said...

Hi Karthik,

Please Check this i hope this will Help You

OAF - Submit a OAF Page using javascript
OAF code using OAScriptBean
OAPageButtonBarBean oapagebuttonbarbean = (OAPageButtonBarBean)webBean.findChildRecursive("PageButtons");

OASubmitButtonBean oasubmitbuttonbean = (OASubmitButtonBean)oapagebuttonbarbean.findChildRecursive"GenerateSignature");

oasubmitbuttonbean.setOnClick("javascript:return test();");

This function is written in the JavaScript file which was included as follows
OAWebBeanFactory oawebbeanfactory = pageContext.getWebBeanFactory();

OAScriptBean oascriptbean = (OAScriptBean)oawebbeanfactory.createWebBean(pageContext, "SCRIPT_BEAN");


The above code is written in Controller.

In the JavaScript function generate value and submit the page as below..

Thanks ,


Karthick said...

Hi Chintan,

Thanks for the reply. Now i am able to call the Javascript function in the js file from the page controller.

But the jquery library files are not getting loaded and the console is showing error while the function inside the file xx_demo_oaf_customization.js is being executed.

Is it sufficient to use PageContext.putJavaScriptLibrary to load the lib files or should we call them seperately like calling the js function from the controller?