How to partially reload a ui:repeat?

天大地大妈咪最大 提交于 2019-11-28 22:46:39

问题


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 items; then the user can click on some kind of "show more" button and 10 more items are displayed through ajax. The user can click the "show more" button until there is no more items to show. Note: This is not pagination, the displayed list gets longer with each click on "show more".

In fact, when the user clicks on the button, the server returns the old items and the new ones, and the client side of JSF must rebuild the whole repeater through jQuery each time.

We would like to find a better and more performant solution. The old items don't change between the n-1 and the n call, so it would be more efficient if the server could only return through ajax the 10 new items.

Is it possible in JSF2 ? JSF seems not really compliant with this kind of recursive rendering. The only component that maybe could help us would be a TreeNode component, but it seems a bit of a hack :-/


回答1:


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'




回答2:


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}));
    }
}


来源:https://stackoverflow.com/questions/11364006/how-to-partially-reload-a-uirepeat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!