简体   繁体   中英

How to target a commandLink nested inside an ui:repeat, in a composite component?

I'm trying to create a paginator composite component. The component should render a commandLink for each available page. It looks something like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:cc="http://java.sun.com/jsf/composite"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    <cc:interface>
        <cc:attribute name="action" targets="jumpButton" required="true"/>
        <cc:attribute name="bean" type="java.lang.Object" required="true"/>
    </cc:interface>
    <cc:implementation>
        <ui:repeat value="#{cc.attrs.bean.pages}" var="page">
            <h:commandLink id="jumpButton"
                           actionListener="#{cc.attrs.bean.jumpToPage(page)}">
                <h:outputText value="#{page}"/>
            </h:commandLink>
        </ui:repeat>
    </cc:implementation>
</html>

The component is used in various pages like this:

<ccc:paginator bean="#{myBean}"
               action="/index?faces-redirect=true&amp;includeViewParams=true"/>

Or:

<ccc:paginator bean="#{myOtherBean}"
               action="/dir/index?faces-redirect=true&amp;includeViewParams=true"/>

Notice the use of faces-redirect=true and includeViewParams=true, which as far as I know cannot be used directly on the commandLinks in the composite component.

The problem is that jumpButton cannot be target because it is inside an ui:repeat. I get the message:

javax.servlet.ServletException: /index?faces-redirect=true&includeViewParams=true : Unable to re-target MethodExpression as inner component referenced by target id 'jumpButton' cannot be found.

If I create a command link with id="jumpButton" outside the ui:repeat, the composite component and button works fine. How can I make my composite component work with the command link inside the ui:repeat?

Solution

The managed bean's jumpToPage action:

public String jumpToPage(String path, Integer page) {
    ...
    setCurrentPage(page);
    return path;
}

The composite component:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:cc="http://java.sun.com/jsf/composite"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    <cc:interface>
        <cc:attribute name="bean" type="java.lang.Object" required="true"/>
        <cc:attribute name="path" type="java.lang.String" required="true"/>
    </cc:interface>
    <cc:implementation>
        <ui:repeat value="#{cc.attrs.bean.pages}" var="page">
            <h:commandLink id="jumpButton"
                           action="#{cc.attrs.bean.jumpToPage(cc.attrs.path, page)}">
                <h:outputText value="#{page}"/>
            </h:commandLink>
        </ui:repeat>
    </cc:implementation>
</html>

Component usage examples:

<ccc:paginator bean="#{myBean}"
               path="/index?faces-redirect=true&amp;includeViewParams=true"/>
<ccc:paginator bean="#{myOtherBean}"
               path="/dir/index?faces-redirect=true&amp;includeViewParams=true"/>

You should remove the action attribute within <cc:interface> . It is not needed since you invoke the action via the bean attribute.

Update 1

And the outcome of the action you can also define as return value of your bean. Like this:

public class MyBean {
    public String jumpToPage(int page){
       // ...
       return "/index?faces-redirect=true&amp;includeViewParams=true";
    }
}

And then use action instead of actionListener :

 <h:commandLink id="jumpButton" action="#{cc.attrs.bean.jumpToPage(page)}">
     <h:outputText value="#{page}"/>
 </h:commandLink>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM