Wednesday, August 5, 2015

Facebook's ReactJS: Finding its own space


React is a one of the most talked about Javascript frameworks of 2015 and in some way it has made its own space amongst the bigger frameworks in market currently.

Facebook's React is filling in gaps where there was a serious room for improvement i.e. the view portion of MVC. Different frameworks in past and present didn't seem to fit in with any other framework as well as React does now. Well ! I would be wrong in saying if React is actually a framework by itself as most part of it its just the view but for a Javascript developer MVC is what it is for 80% of the time.

So where does React 
"V" framework fits in ?

Lets say you are building a heavy component like a grid in a popular AngularJS, it would limit you in some way on how much bigger you can actually build it without hitting the huge watchers count along the way. Just googling for "Angular Grid" will give you a bunch of grids which have a lot of performance issues when the number of rows increases beyond a 1000 using the famously infamous ng-repeat

Before React came into picture many performance workarounds for Angular came from using some sort of DOM manipulating libraries manipulating it in directives but these libraries didn't fill in as a "V" framework. In a world of microservices view frameworks like React actually make a lot of sense as something which you could rely on for getting you out of a trench if you do fall while going full steam on an existing full blown framework.

Web is hellbent comparing "React Vs Angular Vs Ember Vs Backbone Vs NoMatterWhat" - Please don't compare, its not even Apples and Oranges.

To me react is complimentary to existing frameworks if you want to make your view component to be fast, faster or real fast.... Just to give a scale on how fast it is - in my recent encounter with ng-repeat the performance improvement from porting a tree component to react was about 200% .

In the following example React.render() function is used to render the react component within an angular directive. The function also does 2 way communication between Angular and React.

/** @ngInject */ function FastComponent($window) { return { restrict: 'E', scope: { angularCallbackFn: '=', data: '&' }, link: function (scope, el, attrs) { scope.$watchCollection(scope.data,function(newVal,oldValue){ if(newVal !== oldValue){ React.render( React.createElement($window.components.FastTree, {data: newVal,callback:scope.angularCallbackFn}), el[0] ); } }); } }; }

Tuesday, July 8, 2014

Omniture tagging with Oracle WebCenter / ADF pages


In this post we will see how to do omniture tagging with Oracle WebCenter  portal pages. Omniture is an industry leading reporting service which is primarily used by enterprises to track user behavior across custom portals. 

Adobe Omniture Analytics tagging is done can be done on various client actions such a loading a page, clicking on a button or even hovering on a text. The tagging is done through a standard omniture javascript library called s_code.js

We need to include the s_code js file as a resource in our pagetemplate and subsequently use the s variable exposed in the file in utility tagging methods. s_code.js file looks something like this and you can get the actual version from Adobe product team once you get access to setup account.















Omniture global configuration properties

We should have these properties configured from database and depending on environment variables.
  1. s_account
  2. s.visitorNamespace
  3. s.trackingServer
  4. s.trackingServerSecure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* SiteCatalyst code version: H.25.3.
Copyright 1996-2012 Adobe, Inc. All Rights Reserved
More info available at http://www.omniture.com */
/************************ ADDITIONAL FEATURES ************************
     Plugins
*/

var s_account="xyz-dev"
var s=s_gi(s_account);

/* WARNING: Changing any of the below variables will cause drastic
changes to how your visitor data is collected.  Changes should only be
made when instructed to do so by your account manager.*/

s.visitorNamespace="xyz"
s.trackingServer="track.xyz.com"
s.trackingServerSecure="strack.xyz.com"


Apart from the global variables - omniture requires the pages to define the type of event ( or event name), custom properties and variables. Defining these variables help reporting and segregating the event types and values.

We create a JavaScript method to push event to omniture .


1
2
3
4
5
6
7
8
9
10
11
function tagLinkClick(event) {
    var eventSource = event.getSource();
    var linkName = eventSource.getText();
    var eventName = eventSource.getProperty("eventName");
 s.eVar1 = linkName;
 s.prop1 = linkName;
 s.linkTrackVars = 'eVar1,prop1,events';
 s.linkTrackEvents = eventName;
 s.events = eventName;
 s.tl(this, 'o', 'Click Me');
}



Capturing client events

Last and the easiest step is to call the tagLinkClick javascript method on link click.

1
2
3
4
5
 <af:commandLink text="#{bundle.CLICK_ME}"
  id="cl1" >
 <af:clientAttribute name="eventName" value="eventX"/>
 <af:clientListener method="tagLinkClick" type="action"/>                  
</af:commandLink>


You can then login to omniture account and see the real time reports. Please let me know what you think about the approach. Any comments welcomed.


Monday, June 30, 2014

ADF: jQuery Auto Suggest Implementation


Oracle 11gIn this post we will see how to integrate the one of the jquery's famous plugins, the ui autosuggest component with an Oracle Webcenter application using ADF faces. This implementation assumes that the requirements around the autosuggest doesn't meet the requirements of the af:autoSuggestBehavior. So lets first discuss why is the out of box auto suggest behaviour in behavior in adf not that desirable.



Cases where af:autoSuggestBehavior is useful

  1. If you have a large complex dataset ( in tunes of +5000 objects)
  2. If the performance / experience of the autosuggest is not a concern

Cases where custom implementation is useful

  1. The autoSuggestBehavior is not a "client only" side implementation so every change in the value triggers an expensive backend call even if there is a static list of values.
  2. Not every time we require to fetch data from backing bean, there are times and I believe for most of the cases we already know the data for which we are applying autoSuggest.
  3. The lack of flexibility to add custom behavior to suggested output is difficult.


So lets build our awesome autosuggest. Assume we have a requirement of auto-suggesting the user from a list of countries. Here's the steps

Step 1 : Add required libraries to our template


Libraries required:
  1. Add jquery core library, if not present already
  2. Add jquery ui custom library ( including the autosuggest plugin )
  3. Also we need GSON jar in classpath ( optional ). Its useful to flush out JSON in proper format

1
2
<af:resource type="javascript" source="/js/jquery-1.11.0.min.js"/>
<af:resource type="javascript" source="/js/jquery-ui-1.10.1.custom.min.js"/>

Step 2: Add a clientListener

The clientListener will fire a client event on focus to a javascript method suggestContries

1
2
3
4
5
6
<af:inputText label="#{bundle.COUNTRIES}" id="it1"
  clientComponent="true" styleClass="countriesBox"
  value="#{myBean.country}"
  immediate="false">
 <af:clientListener method="suggestCountries" type="focus"/>
</af:inputText>


Step 3: Add a method in backing bean


Lets create a method in our backing bean to initialize the data for autosuggest. The method flushes out javascript variable data to the client.The flushed out data contains the list of countries in JSON format. On executing the method we get the JSON string in a JS variable called countriesJS


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public void getCountriesJSON() {
 
 StringBuilder sb1 = new StringBuilder();
 try {
  /*
  * Get all countries:
  */
  //TODO: replace retrieveCountries method to get the set of CountryData objects
  Set<CountryData> countries = retrieveCountries();
  // create an instance of JsonArray
  JsonArray countriesJsonArray = new JsonArray();           
  sb1.append(" countriesJS=");
  Iterator<CountryData> iter = countries.iterator();

  while (iter.hasNext()) {
   CountryData countryData = iter.next();
   JsonObject countryDataObjJson = new JsonObject();

   countryDataObjJson.addProperty("label", countryData.getCountryName());
   countryDataObjJson.addProperty("value", countryData.getCountryCode().trim());

   countriesJsonArray.add(countryDataObjJson);
   }


  sb1.append(countriesJsonArray.toString());

 } catch (Exception e) {
  e.printStackTrace();
 }
 /*
  * Utility method to add the product json object to client page
  */
 addScriptOnRequest(sb1.toString());
}


Utlity method to add script on request:


1
2
3
4
5
6
public static void addScriptOnRequest(String script) {
 FacesContext context = FacesContext.getCurrentInstance();
 ExtendedRenderKitService erks = 
 Service.getRenderKitService(context, ExtendedRenderKitService.class);
 erks.addScript(context, script);
}

Step 4: Get the data on page load


Now lets add the following code to the page where you have the autosuggest input box. This piece of code will call getCountriesJSON method in your backing bean and load the JSON data on the client.


1
2
3
4
<af:document id="d1" title="#{bundle.MY_COUNTRIES}">
 <af:clientListener type="load" method="loadCountriesOnLoad"/>
 <af:serverListener type="loadCountriesEvt" method="#{myBean.getCountriesJSON}"/>
</af:document>


Add loadCountriesOnLoad Javascript method


1
2
3
4
5
6
 function loadCountriesOnLoad(evt)
{
 var customEvent = new AdfCustomEvent(evt.getSource(),"loadCountriesEvt",{}, true); 
 customEvent.preventUserInput();
 customEvent.queue(true);
}


So when page loads we will have the countriesJS is assigned to the following JSON


1
2
3
4
[
    {"label":"Afghanistan", "value":"AFG"}, 
    {"label":"Albania", "value":"ALB"}
]


Step 5: Wiring everything up


We will write the final JavaScript method mentioned on the onFocus event mentioned in Step 1
 - suggestCountries


1
2
3
4
5
6
7
8
9
10
11
12
13
14
function suggestCountries(evt) {
    var src = document.getElementById(evt.getSource().getClientId() + '::content');
    countriesComp = $(src).autocomplete( {
        "source" : countriesJS, "minLength" : 2,autoFocus: false,
        select : function (event, ui) {
           
        }
    }).autocomplete( "instance" )._renderItem = function( ul, item ) {
      return $( "<li>" )
        .append( "<a>" + item.label + "<br>" + item.value + "</a>" )
        .appendTo( ul );
    };
    
}


so here you go, we have the all client side auto suggest implemented !!! Please let me know what you think about the approach.


Friday, June 27, 2014

ADF Code Examples: af:selectOneChoice


Oracle 11gThis component generates a menu link with a single menu selection model. The value that goes to backing bean by default is an index (0,1,2) unless the valuePassThru is true. If valuePassThru is false then the selection value is based on indices. I am trying to use as much properties in the examples but please free to use them selectively.



Populating af:selectOneChoice  using af:forEach

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<af:selectOneChoice id="sc1" clientComponent="true"
  required="false" immediate="true" 
  shortDesc="#{bundle.TYPES}"
  showRequired="true" mode="default" 
  contentStyle="width:30px" 
  binding="#{pageFlowScope.myBean.types}"
  value="#{pageFlowScope.myBean.type}"
  unselectedLabel="#{bundle.SELECT_ONE}"
  label="#{sprportalBundle.TYPES}:"
  autoSubmit="false">
 <af:forEach items="#{bindings.typeLOV.iteratorBinding.allRowsInRange}"
   var="item">
  <f:selectItem id="sit1" itemLabel="#{item.type}"
    itemValue="#{item.type}"/>
 </af:forEach>
</af:selectOneChoice>


Populating af:selectOneChoice  using individual af:selectItem tags

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<af:selectOneChoice label="#{bundle.MYLABEL}"
  id="xs1" required="false"
  immediate="true"
  valueChangeListener="#{pageFlowScope.myBean.typesVCL}"
  showRequired="true"
  value="#{pageFlowScope.myBean.type}"
  binding="#{pageFlowScope.myBean.typeBinding}"
  styleClass="classname">
 <af:selectItem label="#{bundle.CHOICE_TYPE1}"
   value="#{pageFlowScope.myBean.typeValue1}"
   id="xs2"/>
 <af:selectItem label="#{bundle.CHOICE_TYPE1}"
   value="#{pageFlowScope.myBean.typeValue2}"
   id="xs3"
   rendered="#{pageFlowScope.myBean.typeValueShown}"/>
</af:selectOneChoice>

Populating af:selectOneChoice  using af:selectItems tag


1
2
3
4
5
6
7
8
 <af:selectOneChoice value="#{bindings.Team.inputValue}"  label="#{bundle.MYLABEL}"                      
  shortDesc="#{bindings.type.hints.tooltip}" id="xc2"
  binding="#{pageFlowScope.myBean.team}" autoSubmit="true"
  unselectedLabel="#{bundle.MYLABEL}"
  rendered="#{not pageFlowScope.myBean.noTeams}"
  simple="true">
 <f:selectItems value="#{bindings.Team.items}" id="xc3"/>
</af:selectOneChoice>


ADF Code Examples: af:commandButton [deprecated]


Oracle 11gThis post provides different flavors of af:commandButton usage however the component itself has been deprecated in favor of af:button (super button) in 12c. A command button generates an action event  on the server following a button press which largely differs from the behavior of a goButton.



Using af:commandButton to call an action method with params in your bean


1
2
3
4
5
6
7
8
9
<af:commandButton text="#{bundle.MY_BUTTON}"
  id="cl1"
  actionListener="#{myBean.actionMe}"
  partialSubmit="true"
  partialTriggers="cl2"
  rendered="#{myBean.showLink}">
 <af:setActionListener from="#{myBean.oneVariable}"
   to="#{myBean.otherVariable}"/>
</af:commandButton>


Using af:commandButton to open a popup


1
2
3
4
5
<af:commandButton text="#{bundle.MY_BUTTON}" id="cl1"
  partialSubmit="true"
  clientComponent="true">
 <af:showPopupBehavior triggerType="click" popupId="p1"/>
</af:commandButton>

Calling a JavaScript function with af:commandButton


1
2
3
4
5
6
7
8
9
 <af:commandButton text="#{bundle.MY_BUTTON}"
  id="cl1" 
  clientComponent="true"
  partialSubmit="true">
 <af:clientAttribute name="name"
   value="#{myBean.name}"/>
 <af:clientListener method="showAlert"
   type="click"/>
</af:commandButton>


Thursday, June 26, 2014

JDeveloper and its confusing Extension versions

Extensions for JDeveloper are synonymous with plugins for Eclipse only that the former is tied to Oracle Fusion Middleware Products. There are number of fusion middleware products and these products have there own versions, needless to say not all product versions get served with only a single JDeveloper version.

We take an example of Oracle WebCenter Extensions - recently WebCenter Portal PS7 got released, hurray ! excited ! anyways coming back to point - PS7 was released with extension version of 11.1.1.8 and logically ( as well as historically ) you would have a JDeveloper 11.1.1.8 but No ! - you only see a 11.1.1.7 version ??

Now if you are like me then you go to Google and check if  JDeveloper 11.1.1.7 supports WebCenter Extensions 11.1.1.8 and you would be lucky enough to find this great table from JDeveloper' Extensions and a comment from andrejus. Else just follow my que and download JDeveloper from here

VersionRequirementsLinks



11.1.1.8.0.130707.1955oracle.studio (min=11.1.1.7.40.64.93, max=11.1.1.7.999)
oracle.j2ee (min=11.1.1.7.40.64.93, max=11.1.1.7.999)
Download
11.1.1.8.0.130926.1405oracle.studio (min=11.1.1.7.40.64.93, max=11.1.1.7.999)
oracle.j2ee (min=11.1.1.7.40.64.93, max=11.1.1.7.999)
Download
11.1.1.8.0.131217.0204oracle.studio (min=11.1.1.7.40.64.93, max=11.1.1.7.999)
oracle.j2ee (min=11.1.1.7.40.64.93, max=11.1.1.7.999)
Download
11.1.1.8.0.140404.0207oracle.studio (min=11.1.1.7.40.64.93, max=11.1.1.7.999)
oracle.j2ee (min=11.1.1.7.40.64.93, max=11.1.1.7.999)
Download

Now thats a find don't you think :)

Abhinandan Panda
Happy Me ! BTW, I am the one at back

Wednesday, June 25, 2014

ADF Code Examples: af:commandLink [Deprecated]


Oracle 11gThis post provides different flavors of af:commandLink usage however the component itself has been deprecated in favor of af:link in 12c. A command link generates an action event  on the server following a link click which largely differs from the behavior of a goLink.

Using af:commandLink to call an action method with params in your bean


1
2
3
4
5
6
7
8
9
<af:commandLink text="#{bundle.MY_LINK}"
  id="cl1"
  actionListener="#{myBean.actionMe}"
  partialSubmit="true"
  partialTriggers="cl2"
  rendered="#{myBean.showLink}">
 <af:setActionListener from="#{myBean.oneVariable}"
   to="#{myBean.otherVariable}"/>
</af:commandLink>


Using af:commandLink to open a popup


1
2
3
4
5
<af:commandLink text="#{bundle.SUI_RECENT_SEARCHES}" id="cl1"
  partialSubmit="true"
  clientComponent="true">
 <af:showPopupBehavior triggerType="click" popupId="p1"/>
</af:commandLink>

Calling a JavaScript function with af:commandLink


1
2
3
4
5
6
7
8
9
 <af:commandLink text="#{row.header}"
  id="cl1" 
  clientComponent="true"
  partialSubmit="true">
 <af:clientAttribute name="name"
   value="#{myBean.name}"/>
 <af:clientListener method="showAlert"
   type="click"/>
</af:commandLink>