Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSF lazy loading component value

Consider a simple h:outputText component:

<h:outputText value="#{myBean.myValue}"/>

How can I lazy load that value after the page has been rendered, and display custom 'ajax loading' icon instead of the value while this is being done?

I am using PrimeFaces 3.5 in my project so any PF-specific implementation will be welcome.

like image 488
rootkit Avatar asked Mar 13 '13 15:03

rootkit


2 Answers

A suggest to do this by calling remoteCommand after on page load (it is done by setting autoRun attribute to true) and update your outputText.

private String myValue;

// getter and setter

public void initMyValue() {
  // init myValue
}

On page you should have ajaxStatus component for viewing loading image, and your outputText. Also there should be p:remoteCommand component:

<p:ajaxStatus style="width:16px;height:16px;" id="ajaxStatusPanel">  
  <f:facet name="start">  
    <h:graphicImage value="ajaxloading.gif" />  
  </f:facet>
  <f:facet name="complete">  
    <h:outputText value="" />
  </f:facet>  
</p:ajaxStatus>

<h:outputText id="myText" value="#{myBean.myValue}"/>

<p:remoteCommand autoRun="true" actionListener="#{myBean.initMyValue}" update="myText"/>

EDIT: I supposed that you want to lazy load value of outputText because it contains some long running calculations, but if you want to completely deffer rendering of outputText first add boolean property in your backing bean, and set this property to true at the end of initMyValue method:

private boolean loaded;

// getter and setter

public void initMyValue() {
  // init myValue
  loaded = true;
}

on the page reorganize it as follows:

<h:panelGroup id="myPanel" layout="block">
  <h:graphicImage value="ajaxloading.gif" rendered="#{!myBean.loaded}"/>
  <h:outputText value="#{myBean.myValue}" rendered="#{myBean.loaded}"/>
</h:panelGroup>

<p:remoteCommand autoRun="true" actionListener="#{myBean.initMyValue}" update="myPanel"/>
like image 154
partlov Avatar answered Oct 01 '22 12:10

partlov


You can use a BlockUI to conditionally block the component while it loads.

  1. Define a preRenderComponent event on the <h:outputText/>

       <h:outputText id="myText">
          <f:event name="preRenderComponent" id="started"/>
       </h:outputText>
    
  2. Define a <p:blockUI/> with the id of the event as the trigger

       <p:blockUI block="myText" trigger="started" />
    

You can customize the blockui to display an image or whatever.

A word of caution: I presume you require this because you're doing some heavy lifting in the getter of that component. Know that the getter will be called several times in the lifecycle of that page. So hiding the fact that the operation is taking a long time will not change the fact. A better design would be to preload and cache the value for that component in a durable scope, rather than the theatrics of a "loading" throbber.

like image 24
kolossus Avatar answered Oct 01 '22 14:10

kolossus