Class LazyPanel

All Implemented Interfaces:
PartialStateHolder, StateHolder, TransientStateHolder, ComponentSystemEventListener, FacesListener, SystemEventListenerHolder, EventListener

public class LazyPanel extends OutputFamily

The <o:lazyPanel> is a component that defers rendering of its children until the panel has scrolled into view. This is useful for expensive regions below the fold, where building the children would otherwise happen on every page load even though the user may never scroll far enough to see them.

On initial render, the component writes a wrapper element with a placeholder (optional, see "Placeholder" below) and schedules a viewport intersection listener on it via OmniFaces.js, which uses IntersectionObserver when available and falls back to scroll/resize/orientationChange listeners otherwise. As soon as the wrapper intersects the viewport, a single faces.ajax.request targeting its own client id is fired. During that request, the component detects the trigger, invokes the optional listener with a LazyPanelEvent argument, flips its loaded flag, and renders its children in place of the placeholder.

Usage

 <o:lazyPanel>
     <h:dataTable value="#{bean.expensiveList}" var="row">
         ...
     </h:dataTable>
 </o:lazyPanel>
 

The loaded attribute is a server-side escape hatch: when true, the children are rendered immediately without any client side observer. This is useful for print views, SEO crawlers, or tests.

Listener

The listener attribute can be used to invoke a bean method with an optional LazyPanelEvent argument. It is invoked exactly once, when the component is triggered by the client side intersection.

 <o:lazyPanel listener="#{bean.load}">
     ...
 </o:lazyPanel>
 

The listener is invoked from decode(FacesContext), which then jumps straight to the render response phase. The component therefore effectively behaves like a UICommand with immediate="true": the process validations, update model values and invoke application phases are skipped for the lazy panel ajax request, so any concurrently submitted input values in the enclosing form are not processed, validated, or applied. If you need those values on the server, submit them through a separate ajax request before the lazy panel triggers.

Request parameters

Nested <f:param> or <o:param> children are sent along with the lazy panel ajax request and can be retrieved by the listener via Faces.getRequestParameter(String). This is useful to pass context (like an entity id, filter key, or page number) so that a single listener can serve multiple panels.

 <o:lazyPanel listener="#{bean.load}">
     <f:param name="productId" value="#{product.id}" />
     ...
 </o:lazyPanel>
 

Parameter values are evaluated at initial render (snapshot semantics), consistent with UIParameter usage elsewhere in Faces. For values that must be fresh at trigger time, read them from the surrounding bean state in the listener itself.

Layout

By default the wrapper is rendered as a <div>. Set layout="inline" to render a <span> instead:

 <o:lazyPanel layout="inline">
     ...
 </o:lazyPanel>
 

Placeholder

To show a skeleton or spinner while the lazy region is still off-screen, put it in a facet named placeholder:

 <o:lazyPanel>
     <f:facet name="placeholder">
         <div class="skeleton">Loading...</div>
     </f:facet>
     ...
 </o:lazyPanel>
 
Since:
5.3
Author:
Bauke Scholtz
See Also:
  • Field Details

    • COMPONENT_TYPE

      public static final String COMPONENT_TYPE
      The component type, which is "org.omnifaces.component.output.LazyPanel".
      See Also:
    • EVENT_VALUE

      public static final String EVENT_VALUE
      The omnifaces event value, which is "loadLazyPanel".
      See Also:
    • PLACEHOLDER_FACET_NAME

      public static final String PLACEHOLDER_FACET_NAME
      The name of the facet used to render a placeholder while the children are not yet loaded.
      See Also:
  • Constructor Details

    • LazyPanel

      public LazyPanel()
  • Method Details

    • decode

      public void decode(FacesContext context)
      If this is a lazy panel request targeting this component, then invoke the listener, if any, flip the loaded flag, and jump straight to the render response phase.
      Overrides:
      decode in class UIComponentBase
    • encodeChildren

      public void encodeChildren(FacesContext context) throws IOException
      Always writes the wrapper element with the component client id so that the ajax partial update can replace it, then renders either the placeholder (when not yet loaded) or the actual children.
      Overrides:
      encodeChildren in class UIComponentBase
      Throws:
      IOException
    • getLayout

      public String getLayout()
      Returns the layout of the wrapper element. Supported values are "block" (renders a <div>) and "inline" (renders a <span>). Default is "block".
      Returns:
      The layout of the wrapper element.
    • setLayout

      public void setLayout(String layout)
      Sets the layout of the wrapper element. Supported values are "block" (renders a <div>) and "inline" (renders a <span>).
      Parameters:
      layout - The layout of the wrapper element.
    • getListener

      public MethodExpression getListener()
      Returns the method expression to invoke when the lazy panel is triggered. The method may optionally accept a LazyPanelEvent argument.
      Returns:
      The listener method expression, or null if none was specified.
    • setListener

      public void setListener(MethodExpression listener)
      Sets the method expression to invoke when the lazy panel is triggered.
      Parameters:
      listener - The listener method expression.
    • isLoaded

      public boolean isLoaded()
      Returns whether the children have been loaded. This is true when the component has been triggered by an intersection, or when the loaded attribute has been explicitly set to true by the user (server-side escape hatch). Default is false.
      Returns:
      Whether the children have been loaded.
    • setLoaded

      public void setLoaded(boolean loaded)
      Sets whether the children are considered loaded and should be rendered immediately. This can be used as a server-side escape hatch for print views, SEO crawlers, or tests.
      Parameters:
      loaded - Whether the children have been loaded.
    • getStyleClass

      public String getStyleClass()
      Returns the CSS style class to render on the wrapper element.
      Returns:
      The CSS style class to render on the wrapper element.
    • setStyleClass

      public void setStyleClass(String styleClass)
      Sets the CSS style class to render on the wrapper element.
      Parameters:
      styleClass - The CSS style class to render on the wrapper element.
    • isLazyPanelRequest

      public static boolean isLazyPanelRequest(FacesContext context)
      Returns true if the current request is triggered by a lazy panel ajax request.
      Parameters:
      context - The involved faces context.
      Returns:
      true if the current request is triggered by a lazy panel ajax request.