JSF复合组件 - 尝试保存状态时的奇怪行为

时间:2012-10-22 16:45:25

标签: jsf-2 composite-component state-saving

我正在使用Glassfish 3.2.2和JSF 2.1.11

我正在尝试创建一个复合组件,它将字符串和最大字符数作为参数,然后只显示最大字符数,但它旁边会有一个“更多”链接,单击时会将文本扩展为全长,然后在其旁边显示“less”链接,将其恢复为最大字符数。

我看到一些奇怪的行为,所以我想知道我做错了什么。

这是我的复合组件定义:

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:composite="http://java.sun.com/jsf/composite"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:fn="http://java.sun.com/jsp/jstl/functions"
  xmlns:p="http://primefaces.org/ui">
<composite:interface componentType="expandableTextComponent">
    <composite:attribute name="name" required="true"/>
    <composite:attribute name="maxCharacters" required="true"/>
    <composite:attribute name="value" required="true"/>
</composite:interface>

<composite:implementation>
    <h:panelGroup id="#{cc.attrs.name}">
        <h:outputText value="#{fn:substring(cc.attrs.value, 0, cc.attrs.maxCharacters)}" rendered="#{fn:length(cc.attrs.value) le cc.attrs.maxCharacters}"/>

        <h:outputText value="#{fn:substring(cc.attrs.value, 0, cc.attrs.maxCharacters)}" rendered="#{fn:length(cc.attrs.value) gt cc.attrs.maxCharacters and !cc.expanded}" style="margin-right: 5px;"/>
        <h:outputText value="#{cc.attrs.value}" rendered="#{fn:length(cc.attrs.value) gt cc.attrs.maxCharacters and cc.expanded}" style="margin-right: 5px;"/>
        <p:commandLink actionListener="#{cc.toggleExpanded()}" rendered="#{fn:length(cc.attrs.value) gt cc.attrs.maxCharacters}" update="#{cc.attrs.name}">
            <h:outputText value="#{__commonButton.more}..." rendered="#{!cc.expanded}"/>
            <h:outputText value="#{__commonButton.less}" rendered="#{cc.expanded}"/>
        </p:commandLink>
</h:panelGroup>
</composite:implementation>
</html>

这是Java组件:

@FacesComponent("expandableTextComponent")
public class ExpandableTextComponent extends UINamingContainer
{
    boolean expanded;

    public boolean isExpanded()
    {
        return expanded;
    }

    public void toggleExpanded()
    {
        expanded = !expanded;
    }
}

不幸的是,每次调用toggleExpanded函数时,expand都是false。

但是,如果我将复合组件更改为以下内容,则可以正常工作。

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:composite="http://java.sun.com/jsf/composite"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:fn="http://java.sun.com/jsp/jstl/functions"
  xmlns:p="http://primefaces.org/ui">
<composite:interface componentType="expandableTextComponent">
    <composite:attribute name="name" required="true"/>
    <composite:attribute name="maxCharacters" required="true"/>
    <composite:attribute name="value" required="true"/>
</composite:interface>

<composite:implementation>
    <h:panelGroup id="#{cc.attrs.name}">
        <h:outputText value="#{fn:substring(cc.attrs.value, 0, cc.attrs.maxCharacters)}" rendered="#{fn:length(cc.attrs.value) le cc.attrs.maxCharacters}"/>

        <h:outputText value="#{fn:substring(cc.attrs.value, 0, cc.attrs.maxCharacters)}" rendered="#{fn:length(cc.attrs.value) gt cc.attrs.maxCharacters and !cc.expanded}" style="margin-right: 5px;"/>
        <p:commandLink actionListener="#{cc.toggleExpanded()}" rendered="#{fn:length(cc.attrs.value) gt cc.attrs.maxCharacters and !cc.expanded}" update="#{cc.attrs.name}" process="@this">
            <h:outputText value="#{__commonButton.more}..."/>
        </p:commandLink>

        <h:outputText value="#{cc.attrs.value}" rendered="#{fn:length(cc.attrs.value) gt cc.attrs.maxCharacters and cc.expanded}" style="margin-right: 5px;"/>
        <p:commandLink actionListener="#{cc.toggleExpanded()}" rendered="#{fn:length(cc.attrs.value) gt cc.attrs.maxCharacters and cc.expanded}" update="#{cc.attrs.name}" process="@this">
            <h:outputText value="#{__commonButton.less}"/>
        </p:commandLink>
    </h:panelGroup>
</composite:implementation>
</html>

如果我在toggleExpanded函数中放置一个断点,它只会在“more”链接上调用,而不是在“less”链接上调用。所以问题是当我点击“less”链接时为什么不调用它?这段代码不应该等同于上面的代码吗?

有没有更好的方法来保存组件中的状态?

1 个答案:

答案 0 :(得分:5)

基本上,当您向组件添加自定义属性/属性时,您应该根据他们的文档覆盖UIComponent#saveState()restoreState(),这些属性/属性应该在同一视图上的多个HTTP请求中存活。组件实例即在每个请求上重新创建。

从JSF 2.0开始,更好的方法是直接在属性getters / setters中使用StateHelper。它可以通过继承的UIComponent#getStateHelper()方法获得。

private enum PropertyKeys {
    expanded;
}

public void toggleExpanded() {
    setExpanded(!isExpanded());
}

public void setExpanded(boolean expanded) {
    getStateHelper().put(PropertyKeys.expanded, expanded);
}

public boolean isExpanded() {
    return (boolean) getStateHelper().eval(PropertyKeys.expanded, false);
}