You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by Nicolas Labrot <ni...@gmail.com> on 2013/02/16 23:14:27 UTC

Duplicate id on stylesheet inserted with ResourceDependency

Hello,

I'm glad to post my first message on this ml ;)

I have the infamous but well known duplicate id behaviour with the
following code:
    <h:form>
        <p:commandButton action="#{sessionBean.add}" value="add"
update=":myForm"/>
        <p:commandButton action="#{sessionBean.reset}" value="reset"
update=":myForm"/>
    </h:form>

    <h:form id="myForm">
        <c:forEach items="#{sessionBean.values}" var="value">
            <ui:include src="#{value}"/>
        </c:forEach>
    </h:form>

At the beginning "sessionBean.values" is empty.
Action 1 : User clicks on "add", the add action adds "form0.xhtml" to
"sessionBean.values".
Action 2 : User clicks on "add", the add action adds "form1.xhtml" to
"sessionBean.values".

*form0.xhtml contains : *
<p:fileUpload auto="false"  mode="advanced" required="true"
                      fileUploadListener="#{sessionBean.handleFileUpload}"/>
*
*
*form1.xhtml contains :*
<h:outputText value=""/>

My issue is action 2 returns a duplicate id exception:<partial-response>

<error><error-name>java.lang.IllegalStateException</error-name>
<error-message><![CDATA[component with duplicate id "j_id4" found]]>
</error-message></error></partial-response>


j_id4 is the stylesheet of the fileUpload component :
@ResourceDependency(library="primefaces", name="fileupload/fileupload.css"),

This stylesheet is inserted with action 1. And it seems myfaces tries to
insert it with action 2 too.

Do I do something wrong ?

Thanks for your help!

Nicolas

Re: Duplicate id on stylesheet inserted with ResourceDependency

Posted by Nicolas Labrot <ni...@gmail.com>.
Thanks for your answer Leonardo.

It's a bit annoying to not be able to use c:forEach on a dynamic purpose.
Hope it will be fixe on 2.2.

Nicolas



On Sun, Feb 17, 2013 at 12:36 AM, Leonardo Uribe <lu...@gmail.com> wrote:

> Hi
>
> The problem is caused by use c:forEach tag, iterating over something
> that is not "application scoped".
>
> The reason why c:forEach should be avoided in cases like the one
> shown here is Partial State Saving (PSS) algorithm works under the
> assumption that the same view can be generated between requests,
> so when the delta is applied, it can be applied over the same
> components.
>
> The issue has been widely studied and the conclusion has been that
> c:forEach cannot really be fixed because c:forEach does not have an
> underlying UIComponent instance that encapsultate what's inside
> and in that way generate unique stable ids.
>
> Create a custom component that works in MyFaces and Mojarra is not
> really possible, because the component requires to know some
> implementation details.
>
> Is there any solution? maybe something like this (I don't know if the EL
> is correct, but I hope you get the idea):
>
> <c:if test="#{empty sessionBean.values ? false :
> sessionBean.values.get(0)  eq null ? false : sessionBean.values.get(0)
> }">
>     <ui:include src="#{....}"/>
> </c:if>
> <c:if test="#{empty sessionBean.values ? false :
> sessionBean.values.get(1)  eq null ? false : sessionBean.values.get(1)
> }">
>     <ui:include src="#{....}"/>
> </c:if>
>
> And repeat the same code as many times as options you can put
> on sessionBean.values. In that way, PSS algorithm will reserve the
> necessary slots.
>
> In theory, a variant of c:forEach can be created to fix this problem, but
> it requires to store sessionBean.values into delta view state, to ensure
> stability of PSS algorithm. The previous example works because the
> values of src="#{...}" are stored into the state and unique ids are
> generated per each slot (by c:if effect).
>
> Note any variant of c:forEach will add a strong dependency of the code
> with MyFaces, so that's the reason why it hasn't been done before.
>
> Other alternative to make it work is disable PSS, or use
> org.apache.myfaces.REFRESH_TRANSIENT_BUILD_ON_PSS_PRESERVE_STATE
> web config param, but that is one step back, because without PSS the
> state in session will not be optimally used.
>
> regards,
>
> Leonardo Uribe
>
> 2013/2/16 Nicolas Labrot <ni...@gmail.com>:
> > Hello,
> >
> > I'm glad to post my first message on this ml ;)
> >
> > I have the infamous but well known duplicate id behaviour with the
> > following code:
> >     <h:form>
> >         <p:commandButton action="#{sessionBean.add}" value="add"
> > update=":myForm"/>
> >         <p:commandButton action="#{sessionBean.reset}" value="reset"
> > update=":myForm"/>
> >     </h:form>
> >
> >     <h:form id="myForm">
> >         <c:forEach items="#{sessionBean.values}" var="value">
> >             <ui:include src="#{value}"/>
> >         </c:forEach>
> >     </h:form>
> >
> > At the beginning "sessionBean.values" is empty.
> > Action 1 : User clicks on "add", the add action adds "form0.xhtml" to
> > "sessionBean.values".
> > Action 2 : User clicks on "add", the add action adds "form1.xhtml" to
> > "sessionBean.values".
> >
> > *form0.xhtml contains : *
> > <p:fileUpload auto="false"  mode="advanced" required="true"
> >
> fileUploadListener="#{sessionBean.handleFileUpload}"/>
> > *
> > *
> > *form1.xhtml contains :*
> > <h:outputText value=""/>
> >
> > My issue is action 2 returns a duplicate id exception:<partial-response>
> >
> > <error><error-name>java.lang.IllegalStateException</error-name>
> > <error-message><![CDATA[component with duplicate id "j_id4" found]]>
> > </error-message></error></partial-response>
> >
> >
> > j_id4 is the stylesheet of the fileUpload component :
> > @ResourceDependency(library="primefaces",
> name="fileupload/fileupload.css"),
> >
> > This stylesheet is inserted with action 1. And it seems myfaces tries to
> > insert it with action 2 too.
> >
> > Do I do something wrong ?
> >
> > Thanks for your help!
> >
> > Nicolas
>

Re: Duplicate id on stylesheet inserted with ResourceDependency

Posted by Leonardo Uribe <lu...@gmail.com>.
Hi

The problem is caused by use c:forEach tag, iterating over something
that is not "application scoped".

The reason why c:forEach should be avoided in cases like the one
shown here is Partial State Saving (PSS) algorithm works under the
assumption that the same view can be generated between requests,
so when the delta is applied, it can be applied over the same
components.

The issue has been widely studied and the conclusion has been that
c:forEach cannot really be fixed because c:forEach does not have an
underlying UIComponent instance that encapsultate what's inside
and in that way generate unique stable ids.

Create a custom component that works in MyFaces and Mojarra is not
really possible, because the component requires to know some
implementation details.

Is there any solution? maybe something like this (I don't know if the EL
is correct, but I hope you get the idea):

<c:if test="#{empty sessionBean.values ? false :
sessionBean.values.get(0)  eq null ? false : sessionBean.values.get(0)
}">
    <ui:include src="#{....}"/>
</c:if>
<c:if test="#{empty sessionBean.values ? false :
sessionBean.values.get(1)  eq null ? false : sessionBean.values.get(1)
}">
    <ui:include src="#{....}"/>
</c:if>

And repeat the same code as many times as options you can put
on sessionBean.values. In that way, PSS algorithm will reserve the
necessary slots.

In theory, a variant of c:forEach can be created to fix this problem, but
it requires to store sessionBean.values into delta view state, to ensure
stability of PSS algorithm. The previous example works because the
values of src="#{...}" are stored into the state and unique ids are
generated per each slot (by c:if effect).

Note any variant of c:forEach will add a strong dependency of the code
with MyFaces, so that's the reason why it hasn't been done before.

Other alternative to make it work is disable PSS, or use
org.apache.myfaces.REFRESH_TRANSIENT_BUILD_ON_PSS_PRESERVE_STATE
web config param, but that is one step back, because without PSS the
state in session will not be optimally used.

regards,

Leonardo Uribe

2013/2/16 Nicolas Labrot <ni...@gmail.com>:
> Hello,
>
> I'm glad to post my first message on this ml ;)
>
> I have the infamous but well known duplicate id behaviour with the
> following code:
>     <h:form>
>         <p:commandButton action="#{sessionBean.add}" value="add"
> update=":myForm"/>
>         <p:commandButton action="#{sessionBean.reset}" value="reset"
> update=":myForm"/>
>     </h:form>
>
>     <h:form id="myForm">
>         <c:forEach items="#{sessionBean.values}" var="value">
>             <ui:include src="#{value}"/>
>         </c:forEach>
>     </h:form>
>
> At the beginning "sessionBean.values" is empty.
> Action 1 : User clicks on "add", the add action adds "form0.xhtml" to
> "sessionBean.values".
> Action 2 : User clicks on "add", the add action adds "form1.xhtml" to
> "sessionBean.values".
>
> *form0.xhtml contains : *
> <p:fileUpload auto="false"  mode="advanced" required="true"
>                       fileUploadListener="#{sessionBean.handleFileUpload}"/>
> *
> *
> *form1.xhtml contains :*
> <h:outputText value=""/>
>
> My issue is action 2 returns a duplicate id exception:<partial-response>
>
> <error><error-name>java.lang.IllegalStateException</error-name>
> <error-message><![CDATA[component with duplicate id "j_id4" found]]>
> </error-message></error></partial-response>
>
>
> j_id4 is the stylesheet of the fileUpload component :
> @ResourceDependency(library="primefaces", name="fileupload/fileupload.css"),
>
> This stylesheet is inserted with action 1. And it seems myfaces tries to
> insert it with action 2 too.
>
> Do I do something wrong ?
>
> Thanks for your help!
>
> Nicolas