Speed up Primefaces page load with p:remoteCommand partial update

Thursday June 07, 2012 () Last updated May 23, 2016 12:15:12
Primefaces JSF

Consider a Primefaces page with many components and one of the components in the page takes time to load may be because it loads a lot of data or the backing code of the component connects to slow servers. As a result the entire page is blocked and not visible to the user until that one component loads completely.

We overcome this scenario by using Primefaces' p:remoteCommand.

Here is how we set up remoteCommand for our use. Note that PrimeFaces 3.2 stable was used.

<p:remoteCommand  name="update_storms" 
                  process="@this" 
                  update="maintab" 
                  actionListener="#{stormBean.loadStorms}" />

The name attribute of the p:remoteCommand is a bodyless Javascript code that initiates the entire process. The value of actionListener causes the actual partial update of maintab, the attribute ID of our target component, through a call to stormBean.loadStorms of the backing bean.

The JavaScript snippet below is a common sight in many jQuery codes. It is a handler for the jQuery ready event. It calls our update_storms, set as name attribute of remoteCommand, when the page is ready for more manipulation. At this point the page has started to render and has already become visible to the user. We have included this in the head section of the page.

<script type="text/javascript">
    $(document).ready(function() {
        update_storms (); 
    });            
</script>

It is worth mentioning that PrimeFaces uses jQuery and it bundles the library with each new release so there is no need for an explicit include of jQuery in the page.

Our target component is p:tabView with an ID of maintab as mentioned above. Notice from the snippet below that we wrapped tabView with p:outputPanel. outputPanel is required for the partial update process to work. Also its attribute autoUpdate attribute should be set to true.

You may want to revisit your documentation to learn more about the outputPanel.

The ui:repeat element is our slow loading component. It takes its value from a backing code #{stormBean.activeStorms}. This is the primary target of our partial update.

<p:outputPanel autoUpdate="true">
    <p:tabView   id="maintab" 
                    activeIndex="#{stormBean.activeTab}">                   
        <p:tab title="Satellite Imagery">
			<!-- content removed for clarity -->
        </p:tab>

        <p:tab title="Active Storms">
            <ui:repeat value="#{stormBean.activeStorms}" var="storm">
				<!-- content removed for clarity -->
            </ui:repeat>
        </p:tab>
    </p:tabView>
</p:outputPanel>

The backing bean should be sessionScoped. This means that our StormBean object is kept in the session as long as the session is valid which also suggest that reloading/revisiting the page could use previously created objects.

We named the class below as StormBean.java

@ManagedBean
@SessionScoped
public class StormBean 
        implements java.io.Serializable {
    
    public StormBean() {
    }
    
    private List<Storms> activeStorms;
 
	// This is called by p:remoteCommand when page becomes ready.
    public void loadStorms(ActionEvent event) {

		// If not null page is either reloaded or revisited.
		// If null either the session has expired or this is
		// first time load.

        if (activeStorms != null) {
            return;
        }        
        activeStorms = loadStorms ();

    }

	private List<Storms> loadStorms () {
		List<Storms> storms = new ArrayList<>();
		int numStorms;  // set by a function removed 
					// for clarity

		// Time consuming routine
		for (int i=0; i < numStorms; i++) {
			Strom storm = new Storm ();
			// content removed for clarity
			storms.add (storm);
		}
		return storms;
	}

	// Bound to our ui:repeat, returns nothing initially, loads right away.
    public List<Storms> getActiveStorms () {
        return activeStorms;
    }


	// Contained in ArrayList storms
	public class Storms implements java.io.Serializable {
		Stroms () {}
		String name;
		String warning;
		String irImage;
		/*
			Define getters and setters for 
			members
			
		*/
	}

}

When the page starts loading, getActiveStorms() in line 40, returns immediately with an empty list and the rest of the page continue to load. Only when loadStorms() (in line 12) is called by p:remoteCommand that our list gets populated and our ui:repeat updated.

Finally since p:remoteCommand is ajax enabled, p:ajaxStatus component when available inside the body the page, will be displayed to notify the user that an ongoing update is in progress. This is equivalent to Ajax preloader animation. Below is a sample use of ajaxStatus.

<h:panelGroup style="position:fixed;top:60%;left:40%;">
    <p:ajaxStatus>
        <f:facet name="start">
            <h:panelGrid 
                  styleClass="ui-state-default ui-corner-all" >
                           
                <h:graphicImage  value="./images/prog.gif" />
            </h:panelGrid>
        </f:facet>

        <f:facet name="complete">
            <h:outputText value="" />
        </f:facet>
    </p:ajaxStatus>
</h:panelGroup>

That's it good luck.


27,877

Comments (Speed up Primefaces page load with p:remoteCommand partial update)