I have a datatable using rowExpansion.
When the page is loaded, the rowExpansion is not evaluated, which is fine.
When the paginator is used to show the next results or if a submission is done - the rowExpansion evaluation is triggered.
Here is a XHTML example :
<h:form>
<p:dataTable var="data" value="#{bean.dataList}" paginator="true">
<p:column headerText="Details">
<p:rowToggler />
</p:column>
<p:rowExpansion>
<h:panelGroup rendered="#{not empty data.detail}">
<ui:include src="dataDetail.xhtml" />
</h:panelGroup>
</p:rowExpansion>
</p:dataTable>
<h:commandLink id="addData" value="Add data" action="#{bean.addData}" />
</h:form>
I've profiled this flow using visualVM, and used the debugger, to discover that the data.getDetail() method was called during the following JSF phases : (ApplyRequestValuesPhase, ProcessValidationsPhase, UpdateModelValuesPhase), when the paginator was used.
I've come to the deduction that the rowExpansion is part of the view, and is evaluated as a normal component.
Would you mind telling me if it is the expected behaviour for rowExpansion ?
Is there a correct way to prevent the evaluation of the rowExpansion content when using the paginator ?
Thanks for your answers.
NB : I'm using PrimeFaces 5.2.
Related
This question already has answers here:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
(6 answers)
Closed 2 years ago.
When I click addTagButton, everything works well. It updates all three components: tags, tagId and addTagButton.
<p:commandButton id="addTagButton" icon="ui-icon-plus"
action="#{searchBean.addTag}"
update="tags, tagId, addTagButton"
disabled="#{searchBean.tagChoices.size() == 0}">
</p:commandButton>
Here's the table component:
<h:dataTable id="tags" var="tag" value="#{searchBean.tags}">
<h:column>
<div style="text-align:right;">
<h:outputLabel value="#{tag.typeName}:"/>
</div>
</h:column>
<h:column>
<p:inputText id="tag" size="25" value="#{tag.typeValue}"
disabled="#{searchBean.searchForParent}"/>
</h:column>
<h:column>
<p:commandButton id="delTagButton" icon="pi pi-trash"
action="#{searchBean.deleteTag}"
update=":contentForm:tagId, :contentForm:addTagButton, tags">
<f:setPropertyActionListener
target="#{searchBean.tagId}"
value="#{tag.typeName}" />
</p:commandButton>
</h:column>
</h:dataTable>
When i click on delTagButton that is on each row in tags table, action works fine, :contentForm:tagId and :contentForm:addTagButton update fine. But tags table which is where clicked command button exist, does not update.
When a row is deleted, change must reflect in the tags table which does not work.
Now, If I change h:dataTable to p:dataTable or any other primefaces component, it works. I am trying to make it work with h:dataTable.
Primefaces 8.0, JSF 2.5
Look on this simple example:
<h:form id="form">
<h:panelGroup id="wrapper" layout="block">
<h:dataTable id="table" border="1" value="#{testBean.list}" var="person">
<h:column>#{person.name}</h:column>
<h:column>#{person.surname}</h:column>
<h:column>
<p:commandButton id="delTagButton" icon="pi pi-trash"
action="#{testBean.remove(person)}" update="table">
</p:commandButton>
</h:column>
</h:dataTable>
</h:panelGroup>
</h:form>
To really find out what is being updated look in browser console.
If you're trying to update="table" nothing happens (like in your code). If you try to update a parent of the table (which is often a case), you will get an error an error:
SEVERE: Error Rendering View[/example.xhtml]
org.primefaces.expression.ComponentNotFoundException: Cannot find component for expression "wrapper" referenced from "form:table:0:delTagButton".
at org.primefaces.expression.SearchExpressionFacade.cannotFindComponent(SearchExpressionFacade.java:677)
So we could try with "older" parent and realize that update="#form" works! OK, so we want to help to find id="table\wrapper" component. Let try clientId update="form:table". Like with update="table" nothing happens. And no error from PF (so the element can be found). This could mean that h:dataTable cannot be properly re-rendered from inside itself (but I don't want to throw stones:-)). This is often a case with e.g. popups in JSF 3rd party component libraries.
In this particular example I'd say, you have to update form:wrapper (adding form: works) or just #form to get it work. With your code it would be the same. Try to update some table parent or the whole form.
All of above is tested in JSF 2.2, with last RF, an old PF and OmniFaces. But I think the same would be the case with newer versions.
BTW. I didn't know there is JSF 2.5 :-)
I have following code:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
However, when I open the page, it errors as follows:
component identifier must not be a zero-length String
But it is properly printed in the <h:outputText>. How is this caused and how can I solve it?
You can use EL in the id attribute of a JSF component, but the EL variable has to be available during view build time, while the JSF component tree is to be built. However, the <ui:repeat> runs during view render time, while the HTML output is to be generated based on JSF component tree. The <ui:repeat var> is not available during view build time and #{class2.name} evaluates to null which totally explains the error you got. That it works in <h:outputText> is because it runs during view render time.
If you replace <ui:repeat> by <c:forEach>, which runs during view build time, then it'll work as you intented. The <c:forEach> will namely generate physically multiple <h:form> components in the JSF component tree which each generate individually their own HTML output (in contrary to <ui:repeat>, wherein the very same <h:form> component is been reused multiple times to generate HTML output).
<c:forEach var="class2" items="#{bean.list}" varStatus="status">
<h:form id="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</c:forEach>
However, I really wonder why you need to do that. There's usually no need to dynamically assign component IDs. JSF will already ensure the uniqueness of the ID. The below example,
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="form">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
will end up in multiple forms with each an unique ID, suffixed with iteration index of the <ui:repeat>. If you actually need to use #{class2.name} for some JavaScript/jQuery purposes (you did nowhere state the concrete functional requirement in the question for which you thought that this would be the right solution, so it's merely guessing), then just wrap it in a plain vanilla HTML element:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<div id="#{class2.name}">
<h:form id="form">
<h:outputText value="#{class2.name}" />
</h:form>
</div>
</ui:repeat>
Or set it as style class of a JSF component, which is also just selectable via a CSS selector:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="form" styleClass="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
See also:
JSTL in JSF2 Facelets... makes sense?
I have following code:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
However, when I open the page, it errors as follows:
component identifier must not be a zero-length String
But it is properly printed in the <h:outputText>. How is this caused and how can I solve it?
You can use EL in the id attribute of a JSF component, but the EL variable has to be available during view build time, while the JSF component tree is to be built. However, the <ui:repeat> runs during view render time, while the HTML output is to be generated based on JSF component tree. The <ui:repeat var> is not available during view build time and #{class2.name} evaluates to null which totally explains the error you got. That it works in <h:outputText> is because it runs during view render time.
If you replace <ui:repeat> by <c:forEach>, which runs during view build time, then it'll work as you intented. The <c:forEach> will namely generate physically multiple <h:form> components in the JSF component tree which each generate individually their own HTML output (in contrary to <ui:repeat>, wherein the very same <h:form> component is been reused multiple times to generate HTML output).
<c:forEach var="class2" items="#{bean.list}" varStatus="status">
<h:form id="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</c:forEach>
However, I really wonder why you need to do that. There's usually no need to dynamically assign component IDs. JSF will already ensure the uniqueness of the ID. The below example,
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="form">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
will end up in multiple forms with each an unique ID, suffixed with iteration index of the <ui:repeat>. If you actually need to use #{class2.name} for some JavaScript/jQuery purposes (you did nowhere state the concrete functional requirement in the question for which you thought that this would be the right solution, so it's merely guessing), then just wrap it in a plain vanilla HTML element:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<div id="#{class2.name}">
<h:form id="form">
<h:outputText value="#{class2.name}" />
</h:form>
</div>
</ui:repeat>
Or set it as style class of a JSF component, which is also just selectable via a CSS selector:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="form" styleClass="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
See also:
JSTL in JSF2 Facelets... makes sense?
I have following code:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
However, when I open the page, it errors as follows:
component identifier must not be a zero-length String
But it is properly printed in the <h:outputText>. How is this caused and how can I solve it?
You can use EL in the id attribute of a JSF component, but the EL variable has to be available during view build time, while the JSF component tree is to be built. However, the <ui:repeat> runs during view render time, while the HTML output is to be generated based on JSF component tree. The <ui:repeat var> is not available during view build time and #{class2.name} evaluates to null which totally explains the error you got. That it works in <h:outputText> is because it runs during view render time.
If you replace <ui:repeat> by <c:forEach>, which runs during view build time, then it'll work as you intented. The <c:forEach> will namely generate physically multiple <h:form> components in the JSF component tree which each generate individually their own HTML output (in contrary to <ui:repeat>, wherein the very same <h:form> component is been reused multiple times to generate HTML output).
<c:forEach var="class2" items="#{bean.list}" varStatus="status">
<h:form id="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</c:forEach>
However, I really wonder why you need to do that. There's usually no need to dynamically assign component IDs. JSF will already ensure the uniqueness of the ID. The below example,
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="form">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
will end up in multiple forms with each an unique ID, suffixed with iteration index of the <ui:repeat>. If you actually need to use #{class2.name} for some JavaScript/jQuery purposes (you did nowhere state the concrete functional requirement in the question for which you thought that this would be the right solution, so it's merely guessing), then just wrap it in a plain vanilla HTML element:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<div id="#{class2.name}">
<h:form id="form">
<h:outputText value="#{class2.name}" />
</h:form>
</div>
</ui:repeat>
Or set it as style class of a JSF component, which is also just selectable via a CSS selector:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="form" styleClass="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
See also:
JSTL in JSF2 Facelets... makes sense?
I am using JSF2.0 with Prime Faces 3.2. I have a data table with a column that has two command buttons. The second command button is rendered based on a condition. Everything works well until the data table is filtered. Once filtered the first command button without the rendered attribute calls my actionListener without any issues, whereas the second command button with the rendered attribute does not.
PS:The reason i am using f:param intead of setPropertyActionListener is because of a bug in primefaces datatable that passes the wrong row's id when filtered.
Here is my code, any insight into this issue would be great.
<p:column headerText="Column1" filterMatchMode="contains" filterBy="#{item.name}" sortBy="#{item.name}">
<h:outputText value="#{item.name}" style="float:left" />
<span class="inlineButton">
<p:commandButton id="selectBtn" icon="select"
oncomplete="dialog1.show()" actionListener="#{controller.setItem}">
<f:param name="itemId" value="#{item.id}"/>
</p:commandButton>
<p:commandButton id="delBtn" icon="delete"
actionListener="#{controller.setItem}"
oncomplete="delConfirm.show()"
rendered="#{not empty item.id}">
<f:param name="itemId" value="#{item.id}"/>
</p:commandButton>
</span>
</p:column>