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)
Related
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.
I'm facing a a problem with JSF, i have a fragment that is rendered on all pages, and displays the latest entries of a table (~ 10 items). And i want to reuse it on a page that lists all entries.
I put a rendered rule to prevent the all pages version of the element to appear on this page specifically, but still no go, I aways get a "duplicate id found in view" error. The problem seems to lay on the fact that the JSF processor validate the IDs before validating which ones will really be rendered.
Just for information, I'm using the end of the request URI to determine if rendered is True or False.
Ah, and I tried using c:if, but it was useless too.
Edit:
Sample code requested...
i have this xhtml fragment ("tableInclude.xhtml"):
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<ui:fragment>
<p:dataTable var="item" value="#{bean.items}"
emptyMessage="#{msg['table.empty']}"
widgetVar="table" id="listItems" styleClass="tableItems">
<p:column styleClass="span1" style="text-align: center;">
<f:facet name="header">
<i class='fa-icon-picture'/>
</f:facet>
<p:commandLink action="#{bean.itemSelected(item)}" value="#{item.name}"/>
</p:column>
</p:dataTable>
</ui:fragment>
</ui:composition>
Then i run on every page this:
<ui:include src="./tableInclude.xhtml">
i tried to do this:
<ui:fragment rendered="#{request.requestURI != '/context/don't_render_here.xhtml'}">
<ui:include src="./tableInclude.xhtml">
</ui:fragment>
But i still get the duplicated id error even so when i access the "don't_render_here.xhtml" page.
not the best solution, but a quick and dirty: replace ui:fragment with f:subView
I have a home page xhtml where i am including 3 child xhtml based on conditions.
The issue i am facing is , whatever be the scenario,Book.xhtml always gets invoked.
I changed the rendered condition to false or move out to another condition, but the file always gets invoked Due to which its backing bean also is invoked causing unwanted overhead.
Please provide me a solution
<ui:composition template="/xhtml/baseLayout.xhtml">
<ui:define name="browserTitle">
<h:outputText value="HOME PAGE" />
</ui:define>
<ui:define name="header">
<ui:include src="/xhtml/header.xhtml" />
</ui:define>
<ui:define name="bodyContent">
<h:panelGrid width="100%"
rendered="#{pogcore:isRoleAuthorized(BUNDLE.SUPER)}" >
<ui:include src="/xhtml/SuperUser.xhtml" />
</h:panelGrid>
<h:panelGrid width="100%"
rendered="#{pogcore:isRoleAuthorized(BUNDLE.MAINTENANCE)}" >
<ui:include src="/xhtml/Maintenance.xhtml" />
</h:panelGrid>
<h:panelGrid width="100%"
rendered="#{pogcore:isRoleAuthorized(BUNDLE.PRINT)}">
<ui:include src="/xhtml/Book.xhtml" />
</h:panelGrid>
</ui:define>
</ui:composition>
This is happening due to lifecycle of jsf. JSF UIComponents are evaluated during view render time where as jstl tags are evaluated at build time.
So when you use rendered attribute of h:panelGrid it is too late to not invoke managed beans under the included page. To resolve this try having conditions using jstl tag, the following should work for you.
<c:if test="#{bean.yourCondition}">
<h:panelGrid width="100%">
<h:outputText value="#{bean.yourCondition}"/> <!--if this is not getting printed there is smtg wrong with your condition, ensure the syntax, the method signature is correct-->
<ui:include src="/xhtml/Book.xhtml" />
</h:panelGrid>
</c:if>
<c:if test="#{!bean.yourCondition}">
<h:outputText value="#{bean.yourCondition}"/> <!--This should print false-->
</c:if>
The document below describes the details of jstl and jsf lifecycle.
http://www.znetdevelopment.com/blogs/2008/10/18/jstl-with-jsffacelets/
Check the following document to see another way to solve this without using jstl tags.
http://pilhuhn.blogspot.com/2009/12/facelets-uiinclude-considered-powerful.html
Do this:
Always include the sub pages
Put the panelGrid (with the rendered) inside the page that you always include
Why ? Because the inclusion is performed before the rendered is evaluated.
I've used Primefaces multiple times. It's excellent. But this time I don't know why:
I cannot add a growl component, error is: org.primefaces.component.growl.Growl cannot be cast to org.primefaces.component.api.AutoUpdatable
The same for p:messages
It's possibly due to some errors in my facelet. But I compare this to a successful facelet that I wrote before, and I cannot figure out what's the problem. The facelet is question is (delete p:growl and all go well):
<body>
<ui:composition template="./../../WEB-INF/master.xhtml">
<ui:define name="top">
<h:outputText value="#{bundle.ListAccountHolderTitle}"></h:outputText>
</ui:define>
<ui:define name="content">
<h:form>
<p:growl id="growl"/>
<p:dataTable value="#{accountHolderBean.items}" var="holder">
<p:column headerText="Type">#{holder.name}</p:column>
</p:dataTable>
<h:panelGrid columns="2">
Type
<h:inputText id="type1" required="true" value="#{accountHolderBean.selected.type}"/>
Name
<h:inputText id="name1" value="#{accountHolderBean.selected.name}"/>
Field
<h:inputText id="field1" accesskey="f" value="#{accountHolderBean.field}"/>
Value
<h:inputText id="val" accesskey="v" value="#{accountHolderBean.val}"/>
All attributes
<h:outputText id="attrs" value="#{accountHolderBean.allAttributes}"/>
</h:panelGrid>
<p:commandLink update="attrs" actionListener="#{accountHolderBean.update}">Update</p:commandLink>
</h:form>
</ui:define>
</ui:composition>
</body>
org.primefaces.component.growl.Growl cannot be cast to org.primefaces.component.api.AutoUpdatable
This suggests that you've both PrimeFaces 2.x and 3.x libraries in your webapp's runtime classpath. The AutoUpdatable was introduced in PrimeFaces 3.0 while the Growl already exist before in 2.x, but it didn't implement AutoUpdatable until PrimeFaces 3.0.
Cleanup your classpath and get rid of the offending old PrimeFaces 2.x library.
i've got this jsf code
<f:view>
<rich:page pageTitle="My Page" markupType="xhtml">
...
<rich:panel id="content">
<a4j:include viewId="#{MyBacking.viewId}" />
</rich:panel>
and after trying a number of different ways, I've still not managed to place the following correctly in my code:
<rich:effect for="window" event="onload" type="BlindDown" params="targetId:'<different tags depending on where I place this tag>',duration:2.8" />
My aim is to have the changed element in the a4j:included part of the page change but with the effect in use. I've tried putting it in my included page, or just after the f:view and rich:page tags in the calling page but to no avail. The demo doesn't take includes into account so I'm a bit stuck. Thanks
Just target the a panel inside the rich:panel: targetId:'contentPanel'
and then
<rich:panel ..>
<h:panelGroup layout="block" id="contentPanel">
<a4j:include viewId="#{MyBacking.viewId}">
<ui:param name="targetIdParam" value="putYourTargetIdHere" />
</a4j:include>
<h:panelGroup>
</rich:panel>