JSF: duplicate component id exception when including the same facelets tag twice - jsf

I have a facelets tag like this:
<ui:composition>
<h:outputText value="#{label}"/>
<h:inputText id="input" value="#{value}"/>
<h:message for="input"/>
</ui:composition>
Now if I inlcude this facelets tag twice on the same page, I get an exception complaining about duplicate compoment ids. One solution proposed here https://stackoverflow.com/a/21572756/1785730 was to supply a prefix for the id. However, I find it cumbersome having to come up with an id prefix every time I use this facelets tag. By the way, I don't need the id of the h:inputText outside of the tag.
So I'm thinking of two ways how I can fix this:
Is there a way to link the h:message to the h:inputText without having to specify ids?
If not, I could wrap the tag with a NamingContainer. Which element would be appropriate for that? I can't use h:form here, because that tag already goes into a form.

Your page should be like this
<f:view contracts="default" transient="false">
<ui:composition template="/template.xhtml">
<ui:define name="content">
<h:form>
inputs
</h:form>
</ui:define>
</ui:composition>
</f:view>
inside ui composition you should have ui define and in it form and inputs.

Related

Omnifaces TagAttribute Id cannot be used as id

I have the following Facelet Taglib:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:o="http://omnifaces.org/ui"
xmlns:h="http://java.sun.com/jsf/html">
<o:tagAttribute name="id"/>
<h:panelGroup id="#{id}" layout="block" styleClass="idTest">
#{id}
</h:panelGroup>
</ui:composition>
The taglib.xml looks like this:
<tag>
<tag-name>idTest</tag-name>
<source>resources/myProject/tags/idTest.xhtml</source>
</tag>
And the code, where it is used is simply:
<myProject:idTest/>
How can it be, that the following HTML is being rendered:
<div class="idTest">
j_ido489794984_4bf870cd
</div>
Why does my PanelGroup have no id? The id is generated like it is expected based on the documentation of o:tagAttribute, since the content of the div is rendered. But as id it does not work. Why?
This is indeed confusing.
The documentation literally says:
... it will autogenerate an unique ID in the form of j_ido[tagId] where [tagId] is the <o:tagAttribute> tag's own unique ID.
But the actual behavior is more like so:
... it will override any autogenerated ID into the form of j_ido[tagId] where [tagId] is the <o:tagAttribute> tag's own unique ID.
In other words, when JSF itself needs to render the id attribute of a HTML element, usually because it's required by some internal logic further down in the chain, such as <f:ajax> and friends, and there is no explicit ID specified on the tag like so <x:someTag id="fixedId" />, then JSF will by default autogenerate one in the form of j_id[autoIncrementInteger]. But this will go wrong on tagfiles because the autoIncrementInteger may get bumped further by one on each postback depending on the JSF impl and view state configuration used. The <o:tagAttribute> simply attempts to ensure this way that the autogenerated ID stays the same on each postback.
When you edit your test tagfile to add <f:ajax>,
<h:panelGroup id="#{id}" layout="block" styleClass="idTest">
<f:ajax event="click" />
</h:panelGroup>
then you'll see that the generated <div> has an id, because this is technically required by <f:ajax>.
<div id="j_ido-1512689859_13a7e7e3" class="idTest"
onclick="mojarra.ab(this,event,'click',0,0)">
</div>
Or when you swap <h:panelGroup> for e.g. a <h:form> or whatever component which always requires an ID in the client side,
<h:form id="#{id}" styleClass="idTest">
<ui:insert />
</h:form>
then you'll also see that it's generated.
<form id="j_ido-1512689859_13a7e7e3" name="j_ido-1512689859_13a7e7e3" method="post" action="/test.xhtml" class="idTest" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="j_ido-1512689859_13a7e7e3" value="j_ido-1512689859_13a7e7e3" />
...
</form>
In other words, the feature is working fine, but it was simply not used in your specific case because JSF didn't consider it necessary to generate it.
I've in the meanwhile updated the documentation.

JSF 2.3 Facet in Composite Component with wrong ID

I have the following simple code in a composite component (using Mojarra 2.3.9 / Primefaces 7):
<composite:implementation>
<h:form id="form">
<composite:insertChildren />
<ui:fragment rendered="#{!empty cc.facets.actions}">
<div class="actions">
<composite:renderFacet name="actions" />
</div>
</ui:fragment>
</div>
</h:form>
</composite:implementation>
And the following part is used in a page, trying to fill the composite form with life:
<cc:compForm id="mySpecialForm">
<f:facet name="actions">
<p:commandButton
id="myBtn"
value="Submit"
process="#form"
update="#form">
</p:commandButton>
</f:facet>
</cc:compForm>
The form and all the children are rendered correctly and working quite well. But the button in the renderFacet block has - in my opinion - a wrong client ID, because instead of:
mySpecialForm:form:myBtn
the button only gets the following clientId:
mySpecialForm:myBtn
This leads to an error rendering the page:
Cannot find component for expression "#form" referenced from
"mySpecialForm:myBtn".:
org.primefaces.expression.ComponentNotFoundException: Cannot find
component for expression "#form" referenced from
"mySpecialForm:myBtn".
Am i doing something wrong or is this a bug in JSF/Primefaces? I also tried to configure the componentType to an #FacesComponent extending from UIForm, but in this case no form will be rendered at all.
Update 1:
I tried to create a "minimal, reproducible example (reprex)" like mentioned by Kukeltje. All what is needed are those 2 Parts in a web application (both files under resources):
cc/compForm.xhtml:
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:composite="http://xmlns.jcp.org/jsf/composite">
<composite:interface name="compForm" displayName="A composite form">
<composite:facet name="actions" />
</composite:interface>
<composite:implementation>
<h:form id="form">
<composite:insertChildren />
<composite:renderFacet name="actions" />
</h:form>
</composite:implementation>
</html>
compFormTest.xhtml:
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:cc="http://xmlns.jcp.org/jsf/composite/cc">
<cc:compForm id="mySpecialForm">
<h:inputText id="inputParam" value="" />
<f:facet name="actions">
<h:commandButton id="myBtn" value="Test" />
</f:facet>
</cc:compForm>
</html>
All todo is call the .xhtml page: http:localhost/YOUR_APP/compFormTest.xhtml.
After using it (at least with Mojarra JSF implementation), the input field has the following correct client ID mySpecialForm:form:inputParam. But the command button retrieves another client ID outside the form: mySpecialForm:myBtn, what is a bug from my point of view, regarding the JSF VDL: " ... will be rendered at this point in the composite component VDL view.".
But as i downstriped the example files, it is clearly not a primefaces problem, because the wrong client ID is also included, if using the standard h:commandButton component.
Perhaps someone can use the mentioned 2 files above in a MyFaces environment to check if the behaviour differs or is the same?
Or has someone a workaround in mind? Using an additional #FacesComponent and moving the button from facet to the right spot under the form leads to the following "funny" duplicate ID error:
"Cannot add the same component twice: mySpecialForm:form:myBtn" (at least the client ID was what i expected in the first place)

Send parameter to request on every action for composite component

I have a composite component, which has an id I would like to send as a parameter when executing one of many posiible actions inside the composite component. I know I can use something like;
<h:form id="testForm">
<p:commandButton value="#{testReqBean.label}"
actionListener="#{testReqBean.perform()}"
process="#this or #form" update="#form" ajax="true" >
<f:param value="#{cc.attrs.id}" name="CC-Id" />
</p:commandButton>
</h:form>
now, imagine I have many forms or buttons with specific actions inside the composite component... is there a way to define the parameter I want to send in the request just once ? I mean not adding an f:param inside each form/button (depending on the process #form or #this) but one for the whole composite component?
Thanks in advance!
Maybe one solution would be to use viewparam but this only works if you can add a request parameter.
<f:metadata>
<f:viewParam value="#{your_bean.your_property_name}" name="request_param"/>
</f:metadata>
The only problem here is that whoever implements your composite component would have to set the above when needed, but it still an abstraction to this problem of having to set the same property for all components in same page.
I gather that the <h:form> is enclosed in the composite component itself.
Just use a plain HTML hidden input field.
<h:form>
<input type="hidden" name="CC-Id" value="#{cc.attrs.id}" />
...
<p:commandButton />
<p:commandButton />
<p:commandButton />
...
</h:form>
Unrelated to the concrete problem, having an entire form in a composite is kind of strange. This is then food for read: When to use <ui:include>, tag files, composite components and/or custom components?

How to call the same method after every include of a .xhtml page in JSF?

I have the following part of a .xhtml page:
<ui:composition template="./templates/template.xhtml">
<ui:define name="mainContent">
<ui:include src="include/includeAbleEditor.xhtml">
<ui:param name="includeParam" value="MyClass" />
</ui:include>
<ui:include src="include/includeAbleEditor.xhtml">
<ui:param name="includeParam" value="YourClass" />
</ui:include>
</ui:define>
In the "includeAbleEditor.xhtml" I want to call a method after it was included (In this case this should happend two times).
Now I tried to solve it like this: (metadata tag is part of the includeAbleEditor.xhtml)
<f:metadata>
<f:event type="preRenderView" listener="#{editor.onload}" />
<f:attribute name="textFieldId" value="#{includeParam}" />
</f:metadata>
The Problem:
The method is being called only once. But it should be called two times. Once with the parameter "MyClass" and once with "YourClass".
Do you have any suggestions?
Thanks a lot!
There can be only one <f:metadata> in the entire view and it must be in the top level view. Unlike e.g. <f:view>, they don't "extend" each other and all others will be ignored.
You actually don't need it here. It's only necessary whenever you need to attach <f:viewParam> and/or <f:viewAction> to the specific view. The <f:event> doesn't require a <f:metadata>. It will just be hooked to the parent UIComponent. It was during JSF 2.0/2.1 ages (when <f:viewAction> didn't exist) being abused to have a hook to invoke a listener after <f:viewParam> values are being set. It's just for self-documentary purposes being placed in the same <f:metadata> as where all <f:viewParam>s are.
So, just get rid of it.
<f:event type="preRenderView" listener="#{editor.onload(includeParam)}" />
That said, postAddToView is likely a better event to hook this all on. And to avoid "Duplicate component ID" errors over all place later on, consider wrapping it in <f:subview> or making it a composite.
See also:
When using <ui:composition> templating, where should I declare the <f:metadata>?
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Avoiding duplicate ids when reusing facelets compositions in the same naming container

Conditionally including a template file in ui:composition tag

I am using facelets for templating in my jsf application. I would like to including a template file conditionally in ui:composition tag. If user is logged in the template must be "authorized.xhtml" and if the user is not logged in then the template must be "unauthorized.xhtml". Is there a way to do it? Thanks.
<ui:composition template="/templates/unauthorized.xhtml">
<ui:composition template="/templates/authorized.xhtml">
I am using JSF 1.2.
I would try ternary operation on isAuthorized() attribute, if you have one in your log-in bean:
<ui:composition template="#{loginbean.authorized ? '/templates/authorized.xhtml' : '/templates/unauthorized.xhtml'}">
Or use two <h:panelGroup> tags with appropriate rendered values:
<h:panelGroup rendered="#{loginbean.authorized}">
<ui:decorate template="/templates/authorized.xhtml">
</h:panelGroup>
<h:panelGroup rendered="#{not loginbean.authorized}">
<ui:decorate template="/templates/unauthorized.xhtml">
</h:panelGroup>

Resources