开发者

JSF: what is the "correct" way of doing this?

I've been using JSF for a while but there's something that has always confused me. Hopefully someone can help.

Simple example, there's a page that shows a table of "Person"s and when you click on the "Person" name, it takes you to a page to view the details of the "Person".

Typically, I implement a personSearch.jsf page like this:

<h:dataTable value="#{personHandler.persons}" var="person">

    <h:column>
        <h:commandLink action="#{personHandler.show( person.id )}" >
            <h:outputText value="#{person.name}" />
        </h:commandLink>
    </h:column>

</h:dataTable>

And I implement a personView.jsf page like this:

<h:panelGrid columns="2">

    <h:outputText value="Person ID:" />
    <h:outputText value="#{personHandler.selectedPerson.id}" />

    <h:outputText value="Person Name:" />
    <h:outputText value="#{personHandler.selectedPerson.name}" />

</h:panelGrid>

PersonHandler.show(I开发者_Python百科nteger personId) sets personHandler.selectedPerson and then redirects to the personView page.

This all works fine when PersonHandler is a session bean. But I prefer it to be a request scoped bean because the user may have several windows open and I don't want there to be only one selected person per session.

So my question is, what's the "correct" way to do this JSF? I was once able to get what I wanted using a4j:keepAlive on the personHandler, but that always felt like a kludge. Again, this is something I've never understood about JSF.

Any help is greatly appreciated! rob


If the view is supposed to be bookmarkable, pass the person ID as a GET request parameter instead of a POST request "parameter".

<h:outputLink value="viewperson.xhtml">
    <f:param name="id" value="#{person.id}" />
</h:outputLink>

This way you can use two @RequestScoped beans, one for the list and one for the view. You can preload the selected person as follows:

@ManagedProperty(value="#{param.id}")
private Long id;

@PostConstruct
public void init() {
    selectedPerson = personDAO.find(id);
}

If it is not supposed to be bookmarkable, then just create a single view which renders the view state conditionally.

<ui:fragment rendered="#{!personHandler.viewMode}">
    <h:form>
        <h:dataTable value="#{personHandler.persons}" var="person">
            <h:column>
                <h:commandLink value="#{person.name}" action="#{personHandler.show(person)}" />
            </h:column>
        </h:dataTable>
    </h:form>
</ui:fragment>
<ui:fragment rendered="#{personHandler.viewMode}">
    <h:form>
        ...
        <h:commandLink value="Go back" action="#{personHandler.back}" />
    </h:form>
</ui:fragment>

(You can if necessary split out the content of the both framgents to another Facelet files which you include by <ui:include>)

This way you can use a single @ViewScoped bean with action methods returning void or null.

public void show(Person selectedPerson) {
    this.selectedPerson = selectedPerson;
}

public void back() {
    selectedPerson = null;
}

public boolean isViewMode() {
    return selectedPerson != null;
}

You can even wrap the whole view in some

<h:panelGroup id="container">

and nest the following in both command links to let Ajax magic do the work

<f:ajax execute="@form" render=":container" />
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜