X

Technical Articles relating to Oracle Development Tools and Frameworks

  • ADF
    February 24, 2014

Programmatic UI Scrolling in ADF Faces

Duncan Mills
Architect

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(componentId);
  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.

Join the discussion

Comments ( 2 )
  • minsoo jo Tuesday, February 25, 2014

    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


  • Duncan Tuesday, February 25, 2014

    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


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.