JSF composite component - weird behavior when trying to save state

Posted by jc12 on Stack Overflow See other posts from Stack Overflow or by jc12
Published on 2012-10-22T16:45:25Z Indexed on 2012/10/22 17:01 UTC
Read the original article Hit count: 249

I'm using Glassfish 3.2.2 and JSF 2.1.11

I'm trying to create a composite component that will take as parameters a string and a max number of characters and then will show only the max amount of characters, but it will have a "more" link next to it, that when clicked will expand the text to the full length and will then have a "less" link next to it to take it back to the max number of characters.

I'm seeing some weird behavior, so I'm wondering if I'm doing something wrong.

Here is my composite component definition:

<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>

And here is the Java component:

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

    public boolean isExpanded()
    {
        return expanded;
    }

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

Unfortunately expanded is always false every time the toggleExpanded function is called.

However if I change the composite component to the following then it works.

<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>

If I place a breakpoint in the toggleExpanded function, it only gets called on the "more" link and not the "less" link. So the question is why doesn't it get called when I click on the "less" link? Shouldn't this code be equivalent to the code above?

Is there a better way to save state in a component?

© Stack Overflow or respective owner

Related posts about jsf-2

Related posts about composite-component