Programmatic UI Scrolling in ADF Faces

I've been dealing with a use case recently where we needed to synchronize two panels in a user interface, where (in the simple version) selecting an object on one side of the screen would also select a corresponding object in a scrolling area on the other side of the screen and scroll in into view.  the scrolling panel in this case being a panelGroupLayout / scroll, not a table.

Declarative  scrolling is really simple, you can drop a UI element such as commandButton onto the page and then nest, within that, the behavior tag <af:scrollComponentIntoViewBehavior>. This tag is great if you have a long page and want to provide the users with a way to navigate to different sections, however, it needs to be wired to a command component and the user needs to physically invoke the operation.

In this case, everything needed to happen in reaction to a series of complex programmatic events and so, the use of the behavior tag did not cut it.  So I did a small amount of testing to see if it was possible to achieve the same result in a hands off fashion from within java code.

It turns out to be pretty simple to do, but there are different approaches depending on your version:

Programatic Scrolling in 11.1.2.n and 12c

In the newer versions of ADF this issue is addressed head on with a new API on the AdfFacesContext -> scrollComponentIntoView(component, focus);  This API takes a UIComponent reference for the component to scroll to, and the second argument is a boolean flag to indicate if the component should take focus as well (for example if it was an input field).  

Programatic Scrolling in 11.1.1.n

 Prior to ADF Faces 11.1.2 the handy  scrollComponentIntoView() api does not exist, however, we can acheive the same effect using some JavaScript. (Note if you are on a version of ADF that does support the scrollComponentIntoView() Java API then use that, not this.)

As with the behavior tag, you need to do two things.

  1. The target component has to have clientComponent="true" as this scrolling operation all takes place on the client
  2. You need the full id of the target component.  This should include any naming containers such as templates and regions.  The safest way to do this is to call getClientId() on the java component itself. 

 Then you can just invoke this little function.  Note that the code does not have any error handling if you get the component ID wrong so feel free to improve it to make it more robust:

import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service; 

private void scrollIntoView(String componentId){
  StringBuilder builder = new StringBuilder();
  builder.append("var c = AdfPage.PAGE.findComponent('");
  builder.append("'); c.scrollIntoView(true,null);");
  FacesContext fctx = FacesContext.getCurrentInstance();
  ExtendedRenderKitService erks =
    Service.getRenderKitService(fctx, ExtendedRenderKitService.class);
  erks.addScript(fctx, builder.toString());        

If you use this function an it appears not to work you may be hitting a timing issue where the framework is, in turn, resetting the focus after you have set it.  If that seems to be happening in your case, then the solution is to re-write the above JavaScript slightly to execute the scrollIntoView() after a short delay.  You can use a JavaScript  setTimeout() function on the window object to do this.  Delaying the scroll call for about 10ms should be sufficient.


My partner engineer suffers from similar requirement.
How to use this with dragsource?
Customer wants to scroll down when he drag an item to bottom.
The example is google callendar day view. It can drag a task from morning to evening.
can you give me a hint?

Thank you

Posted by minsoo jo on February 25, 2014 at 12:07 AM GMT #

Drag and Drop is a client side activity and this blog article relates to scrolling in response to a server side activity. The scrollIntoView API is a client side API so in theory might help, however, you need to know the component that you are trying to show and it's not clear that you would have that information in the case of a drag and drop operation

Posted by Duncan on February 25, 2014 at 08:44 AM GMT #

Post a Comment:
Comments are closed for this entry.

Hawaii, Yes! Duncan has been around Oracle technology way too long but occasionally has interesting things to say. He works in the Development Tools Division at Oracle, but you guessed that right? In his spare time he contributes to the Hudson CI Server Project at Eclipse
Follow DuncanMills on Twitter

Note that comments on this blog are moderated so (1) There may be a delay before it gets published (2) I reserve the right to ignore silly questions and comment spam is not tolerated - it gets deleted so don't even bother, we all have better things to do with our lives.
However, don't be put off, I want to hear what you have to say!


« June 2016