X

Technical Articles relating to Oracle Development Tools and Frameworks

Pattern For Obtaining ADF Component ID for JavaScript

Duncan Mills
Architect

The following article outlines a technique that I use and has been buried in various code samples in the past.  However, in light of the explicit how-to being asked a couple of times recently, it seems sensible to pull it out into a explicit article. 

Now the scenario here is when you have a piece of JavaScript that needs to operate on a specific client side component. Now in many cases, you will be able to obtain the component that you need by simply calling the getSource() function on the event object that is passed to the function invoked by your <af:clientListener>. In other cases, given that same component reference you can walk up or down the component tree to find the component you need.  However, there are certainly circumstances where you need to grab a component which is kinda outside of the context and it would be much easier if you could just pass in the ID of the component and use the findComponent JS APIs to grab it.

The problem is of course that the ID you use for say a button (let's work with "b1" as an example) is of course not the real ID that would be used on the client to identify the component.  The full ID is going to depend on the various JSF naming containers that the component is nested within.  So our button b1 may end up being identified by something like "tmplt1:r1:b1".  So the question is, how can you easily obtain that full contextual calculated ID in a just-in-time manner so that your JavaScript can call the AdfPage.PAGE.findComponentByAbsoluteId() function to get its client side handle?

The pattern for doing this is pretty simple - you need to do just 5 things:

Step 1

On the component that  needs to be referenced from JS, remember to set clientComponent="true" You'd be amazed how often this is forgotten and leads to much hair pulling out as you just *know* that the client ID is correct but it's not being found!

Step 2

Likewise on the same tag you need to set the binding property so that you can obtain the reference to the component. So for example let's assume we create a backing bean class and set that up. e.g.

<af:button id="b1" clientComponent="true" 
binding="#{backingBeanScope.examplePage.clientButton}">

This would then correspond to the following the backing bean class: 

  private ComponentReference clientButton;
public void setClientButton(RichButton clientButton){
this.clientButton = ComponentReference.newUIComponentReference(clientButton);
}
public RichButton getClientButton(){
if (clientButton != null){
return (RichButton)clientButton.getComponent();
}
else{
return null;
}
}

Step 3

Create a new function in the same backing bean that calls the getClientId() function on the Java reference to the button.  This returns us the full calculated id, including the path defined by any templates, regions or other naming containers.

  public String getClientButtonClientId(){
    FacesContext ctx = FacesContext.getCurrentInstance();
    return this.getClientButton().getClientId(ctx);
  }

Step 4

Now we have a way of getting the correct clientId it needs to be made available to JavaScript, to do this we use an <af:clientAttribute> co-located with the <af:clientListener> that will be triggering the JS. So imagine in this case we have a second button that needs to reference our "b1" button:

<af:button text="Invoke Client Operation" id="b2">
  <af:clientListener method="doSomeClientOp" type="action"/>
  <af:clientAttribute name="b1ClientId"
value="#{backingBeanScope.examplePage.clientButtonClientId}"/>
</af:button> 

So we are passing the full String representation of the client ID for b1 via the attribute called "b1ClientId".

Step 5

All that remains is for the JavaScript function that is being called to get hold of this b1ClientId value that is being passed in (add error handling of course).

function doSomeClientOp(actionEvent){
  var actionComp = actionEvent.getSource();
  var b1ClientId = actionComp.getProperty("b1ClientId"); 
  var b1ComponentRef = AdfPage.PAGE.findComponentByAbsoluteId(b1ClientId);
  ...

Additional Thoughts

In the steps here, I have used the pattern of utilizing the binding attribute on the component to provide the Java-side component handle.  However, there are of course other ways of getting hold of this reference (e.g. see my previous article Locating JSF components by ID).  The important thing here is the use of the getClientId() api to obtain the correct client ID encoding from the Java component and then making that available in JavaScript.

Join the discussion

Comments ( 1 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha
Oracle

Integrated Cloud Applications & Platform Services