We\'ve got a web application built on JBoss 7.1 with JSF2 and Primefaces 3.3.
On one of our page, there is a ui:repeat
displaying 10 it
For situations like this, I completely bypass JSF and use JAX-RS service with jQuery AJAX. That approach will help you build much better applications than just the AJAX support from JSF. Here is the basic technique.
In the XHTML page, simply have a placeholder for the list:
<div id="item_list"></div>
<a href="#" onclick="loadNext();">Load more...</a>
When the page loads, make an AJAX request to populate the initial list. Here is sample code. There may be typos, but you get the idea.
var nextStart = 0;
$(function() {
loadNext();
});
function loadNext() {
$.ajax({
type: "GET",
url: "api/items?start=" + nextStart,
success: function(data) {
appendToList(data);
nextStart += data.length;
}
});
}
function appendToList(data) {
//Iterate through data and add to DOM
for (var i = 0; i < data.length; ++i) {
$("#item_list").append($("<p>", {text: data.productName}));
}
}
There's nothing like that in the standard JSF API. Also nothing comes to mind in PrimeFaces. For PrimeFaces see the update at the end
The OmniFaces <o:componentIdParam> may however be exactly what you're looking for. It allows you to let JSF render only a subset of the component tree based on a specific request parameter, which can be a component ID or a client ID. You could basically just use jQuery's $.get() to reload the <ui:repeat>
along with the start index as a request parameter and use jQuery's $.append() to append it to the HTML DOM.
Here's a complete kickoff example. The view:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:o="http://omnifaces.org/ui"
>
<f:metadata>
<o:componentIdParam componentIdName="componentId" />
</f:metadata>
<h:head>
<title>Stack Overflow Question 11364006</title>
<script src="http://code.jquery.com/jquery-latest.min.js"></script> <!-- Substitute with PrimeFaces' one, if necessary. -->
</h:head>
<h:body>
<ul id="items">
<ui:repeat id="itemsRepeater" value="#{bean.items}" var="item">
<li>#{item}</li>
</ui:repeat>
</ul>
<input type="button" id="showMore" value="Show more"/>
<h:outputScript>
$("#showMore").click(function() {
$items = $("#items");
var params = { start: $items.find("li").length, componentId: "itemsRepeater" };
$.get(location, params, function(html) {
$items.append(html);
});
});
</h:outputScript>
</h:body>
</html>
The backing bean:
@ManagedBean
@RequestScoped
public class Bean {
private List<String> items;
@ManagedProperty("#{param.start}")
private int start;
@PostConstruct
public void init() {
// Just a stub. Do your thing to fill the items.
items = new ArrayList<String>();
int size = start + 10;
for (int i = start; i < size; i++) {
items.add("item " + (i + 1));
}
}
public void setStart(int start) {
this.start = start;
}
public List<String> getItems() {
return items;
}
}
Update: a live demo can be found in the "Expandable list" example of the <o:componentIdParam> page of current showcase application.
Update 2): PrimeFaces p:datascroller
has lazyloading with 'on demand scrolling'