Partial Rendering will only work with #form? - jsf

I have a strange situation where using #parent, or even explicit id-s dont work in the update attribute. But #form works fine.
I've made a very simple test case, that includes a simple grid whose behaviour is like this :
Every record inside the grid has a modify button
After the modify button is clicked, it'll modify the server data, and the button will be gone, since it'll be only rendered if the record has NOT been modified.
The modify button is like this :
<!-- this works, since it's using #form in the update attribute -->
<p:column>
<p:commandLink
value="modify record"
process="#this"
action="#{testUserBean.modifyRecord(user)}"
update="#form"
rendered="#{not testUserBean.isRecordModified(user)}" />
</p:column>
Notice that the update attribute makes use of #form which makes it work: when the modify button is clicked, it rerenders and disappears.
Substitute it with #this or #parent or the id of the grid, then it will NOT work. For me it's very logical to use the id of the grid in the update attribute, since i would like to refresh the grid after clicking on the buttton.
I tried making use of rowIndexVar="rowIndex" and myGridId:#{rowIndex}:link, but still aint working.
<!-- this does not work -->
<p:column>
<p:commandLink id="link"
value="modify record"
process="#this"
action="#{testUserBean.modifyRecord(user)}"
update="tblUser"
rendered="#{not testUserBean.isRecordModified(user)}" />
</p:column>
Here are the resources for this simple example :
The xhtml file
The JSF Bean file
The user POJO bean
Im using tomcat 7, and these are my dependencies :
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.0.4-b09</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.0.4-b09</version>
<scope>compile</scope>
</dependency>
Tried out primefaces 3.0.M1 also, but it got the same behavior also.
Please share your ideas. Is this a bug or i did something wrong ?
UPDATE
Hello,
I've just finished some testing, but all still fails.
Test 1 (making use of update=":gridRPBDetails") :
The JSF File :
<p:commandLink id="undoLink" value="Undo" process="#this"
action="#{tInputBean.actionUndoRemoveRecord(rpbDetail)}"
update=":gridRPBDetails"
rendered="#{tInputBean.isRemoveRecord(rpbDetail)}"
title="Batalkan buang data" />
The generated xhtml :
<a title="Batalkan buang data" onclick="PrimeFaces.ajax.AjaxRequest('/cashbank/faces/TInput.xhtml',
{formId:'j_idt38',async:false,global:true,source:'gridRPBDetails:0:undoLink',
process:'gridRPBDetails:0:undoLink',update:':gridRPBDetails'});"
href="javascript:void(0);" id="gridRPBDetails:0:undoLink">Undo</a>
Test 2 (making use of update=":gridRPBDetails:#{rowIndex}:undoLink") :
The JSF File :
<p:commandLink id="undoLink" value="Undo" process="#this"
action="#{tInputBean.actionUndoRemoveRecord(rpbDetail)}"
update=":gridRPBDetails:#{rowIndex}:undoLink"
rendered="#{tInputBean.isRemoveRecord(rpbDetail)}"
title="Batalkan buang data" />
The generated xhtml :
<a title="Batalkan buang data" onclick="PrimeFaces.ajax.AjaxRequest('/cashbank/faces/TInput.xhtml',
{formId:'j_idt38',async:false,global:true,source:'gridRPBDetails:0:undoLink',
process:'gridRPBDetails:0:undoLink',update:':gridRPBDetails:0:undoLink'});"
href="javascript:void(0);" id="gridRPBDetails:0:undoLink">Undo</a>
Both tests still fail in terms of clicking the undo button cannot refresh the record of the grid, or even the grid itself.
UPDATE
I've just updated my test using :
<p:commandLink
value="modify record"
process="#this"
action="#{testUserBean.modifyRecord(user)}"
update=":mainForm:tblUser"
rendered="#{not testUserBean.isRecordModified(user)}" />
Notice i used the :mainForm:tblUser, and i've tried the other options and still failed :
:mainForm:tblUser:
:tblUser (when i dont define the form name)
:mainForm:tblUser:#{rowIndex}:linkId
But 1 thing i notice is,nNo matter what i choosed for the update, the update always ends up as tblUser:0
<a onclick="PrimeFaces.ajax.AjaxRequest('/cashbank/faces/test.xhtml',
{formId:'mainForm',async:false,global:true,source:'tblUser:0:j_idt33',
process:'tblUser:0:j_idt33',
update:'tblUser:0'
});" href="javascript:void(0);" id="tblUser:0:j_idt33">modify record</a>
I tried modifying tblUser:0 on the fly using firebug to just tblUser, the partial rendering on the grid works fine.
Im beginning to think that this is a bug when trying to update a grid from inside a grid record.

This has been answered in here.
Here is the quote from the answer :
This is more like a mojarra issue, it should work fine with myfaces
without a wrapper. Workaround is to put a wrapper.
Code:
<h:form id="frm">
<p:outputPanel id="wrapper">
<p:dataTable id="tbl">
//...
<p:commandButton update=":frm:wrapper" />
//...
<p:dataTable>
<p:outputPanel>
</h:form>
Sorry for the late update !

Look at the generated HTML. Since the <p:commandLink> is placed in a <p:dataTable>, its generated client ID is something like this
<a id="someformid:tblUser:0:link">
The 0 is the table row index.
So when you use the relative identifier update="tblUser" on <p:commandLink>, then it will basically search for someformid:tblUser:0:tblUser to update. But this does not exist. You'd like to use an absolute identifier instead, starting with :.
<p:commandLink update=":someformid:tblUser">

<p:dataTable id="mytable"
value="#{dataTableWithLinkBean.list}" var="item">
<p:column>
<f:facet name="header">
Code
</f:facet>
<p:commandLink actionListener="#{dataTableWithLinkBean.viewDetail}"
oncomplete="dlg.show()" process="#this"
update=":mainform:dialog_content">
<h:outputText value="#{item.code}"/>
<f:param name="code" value="#{item.code}"/>
</p:commandLink>
</p:column>
</p:dataTable>
<p:dialog widgetVar="dlg" modal="true" id="dialog"
width="300" height="300">
<h:panelGrid id="dialog_content">
<h:outputText value="#{dataTableWithLinkBean.selectedCode}"/>
</h:panelGrid>
</p:dialog>
Above is the example of link in the datatable that render the dialog.
may be you can try to change
update=":mainform:dialog_content"
to
update=":mainform:mytable"
in this case my tag form is using id mainform, shown as below:
Please note that I've not been trying this. I just have used in my example above to rendering the dialog panel partially. Good luck
Update:
Well I give it a try like this, combine with your updated post
<p:dataTable id="mytable"
value="#{dataTableWithLinkBean.list}" var="item">
<p:column>
<f:facet name="header">
Code
</f:facet>
<h:outputText value="#{item.code}"/>
</p:column>
<p:column>
<p:commandLink value="Modify"
action="#{dataTableWithLinkBean.removeDetail(item)}"
process="#this"
update="mytable"
rendered="#{not dataTableWithLinkBean.isModifier(item)}">
</p:commandLink>
</p:column>
</p:dataTable>
And in the backing bean
public String removeDetail(ClassForTest item){
for(ClassForTest o: list){
if(o.equals(item)){
//do something update to database
item.setModified(true);
break;
}
}
return "";
}
public boolean isModifier(ClassForTest item){
return item.isModified();
}
And it's worked! after I click on the modify button, call the removeDetail method, do some actions, update the modified status. then do update="mytable", and the link modify is gone.
I'm using Mojarra 2.0.4 and primefaces 3.0.M2
FYI, I'm using DataModel in the backing bean, just a simple List
so no rowIndexVar. Maybe when using the DataModel, can produce this problem.

Related

Primefaces 8.0 JSF not updating table [duplicate]

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

<rowExpansion> evaluated during JSF phases

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.

Primefaces form is not updating from within dialog

I have a view like so:
<h:form id="productForm">
<p:messages
id="productFormMessages"
autoUpdate="true"
redisplay="true"
globalOnly="true" />
<p:panelGrid
id="detailsGrid">
<p:row>
...
<p:column>
...
<p:outputLabel
id="fieldToUpdateId"
value="XYZ" />
<p:commandButton
action="#{bean.prepareDialog}"
update="dialogFormId"
oncomplete="PF('dialogModal').show();" />
</p:column>
</p:row>
</p:panelGrid>
</h:form>
<ui:include src="/../.../dialog.xhtml" />
And this is what dialog.xhtml looks like:
<p:dialog
id="dialogId"
widgetvar="dialogModal"
appendTo="#(body)"
modal="true"
dynamic="true">
<h:form
id="dialogFormId">
...a selectOneMenu...
<p:commandButton
id="saveButtonId"
value="Save"
actionListener="#{bean.save}"
oncomplete="PF('dialogModal').hide();"
process="#form"
update=":productForm" />
</h:form>
But the save button just refuses to update the productForm. It does update productFormMessages (which I'm guessing is because of the autoUpdate) but the form just doesn't update. I need to do a page reload from the browser in order for it to reflect the latest data. I have tried many different ways of doing this.
1. Using p:component to directly refer to the outputLabel in the update attribute.
2. (1) also using the form ID and the panelGrid ID.
3. Using the full client ID (with and without the preceeding ':') in the update attribute. Similarly using the form ID and the panelGrid ID.
4. Adding the client ID to the render IDs in the bean and then calling the partialViewContext#update method on that.
4. Setting partialViewContext#setRenderAll to true.
4. And as a last ditch attempt, as demonstrated by the code, updating the entire productForm. Which isn't so bad, because fieldToUpdateId is just one of the fields that I need to update in the form. But either way, it's not working.
Clearly, the data is being saved on the back end, because a page reload gives me the latest data. But I just can't get the dialog to update the form where it's being called from. I'm out of ideas. What am I doing wrong?
Theoretically this should work, But please inspect the button in the Html source, to make sure which part of the html it refresh. it should have something like this.
onclick="PrimeFaces.ab({s:'dialogFormId:saveButtonId1',u:'productForm',onco:function(xhr,status,args){PF('dialogModal').hide();;}});return false;"

primefaces <p:datatable> <p:commandlink> fires another <h:link> accidentally

i got two cases of strange behaviour in my p:dataTable . First when i try to call the h:link with the f:param the link always sends the same id. Always the id from the first entry.
The bigger problem is when i push on the commandbutton the h:link gets called though this behavior was completely not expected. Especially without the right Parameters.
Is this a Bug or am i doing something wrong?
When i delete the h:link everything works like expected.
I would appreciate any help in this matter
My Primefaces Version is 3.5 and im working with Liferay 6.1 on Tomcat 7. With the newest FacesBridge
<h:form id="serviceForm">
<p:dataTable id="newServicesTable" var="service" value="#{cloudServicesBean.newServices}" rowKey="service.serviceId" selection="#{cloudServicesBean.selectedService}">
<p:column headerText="Servicename">
<h:link outcome="/views/cloudservice/overview.xhtml" includeViewParams="true" value="#{service.serviceName}">
<h:outputText value="#{service.serviceId}"/>
<f:param name="selectedServiceId" value="#{service.serviceId}" />
</h:link>
</p:column>
<p:column headerText="Provider">
<h:outputText value="#{adminBean.getOrganizationNameForId(service.providerId)}" />
</p:column>
<p:column headerText="Datum">
<h:outputText value="#{service.createDate}" />
</p:column>
<p:column headerText="Aktionen" rendered="#{adminBean.isUserAdministrator()}">
<p:commandButton icon="ui-icon-check" action="#{cloudServicesBean.setServiceApproved}" update=":serviceForm">
<f:setPropertyActionListener value="#{service}" target="#{cloudServicesBean.selectedService}" />
</p:commandButton>
</p:column>
</p:dataTable>
I had exactly the same problem. I run Primefaces 3.5 with Liferay 6.0.11 on Tomcat 7. When I switched the Liferay JSF dependencies from version 3.1.2.ga3 to 3.1.3-ga4 the issue was resolved.
<dependency>
<groupId>com.liferay.faces</groupId>
<artifactId>liferay-faces-alloy</artifactId>
<version>3.1.3-ga4</version>
</dependency>
<dependency>
<groupId>com.liferay.faces</groupId>
<artifactId>liferay-faces-bridge-impl</artifactId>
<version>3.1.3-ga4</version>
</dependency>
<dependency>
<groupId>com.liferay.faces</groupId>
<artifactId>liferay-faces-portal</artifactId>
<version>3.1.3-ga4</version>

How do I conditionally render an <f:facet>?

I would like to be able to conditionally omit a footer from a PrimeFaces panel element:
<p:panel header="some text">
<f:facet name="footer">
#{message}
</f:facet>
<!-- ... -->
</p:panel>
I hoped that the rendered attribute would work:
<p:panel header="some text">
<f:facet name="footer" rendered="#{!empty message}">
#{message}
</f:facet>
<!-- ... -->
</p:panel>
But the footer is still rendered, with empty content. It appears that facet does not have the rendered attribute: http://www.jsftoolbox.com/documentation/help/12-TagReference/core/f_facet.html.
What's the right way to do this?
I was able to solve this by swapping the facet out for an attribute. To summarize:
This works
<p:panel ...>
<f:attribute name="footer" value="#{message}"/>
<!-- ... -->
</p:panel>
But this doesn't work
<p:panel footer="#{message}">
<!-- ... -->
</p:panel>
Neither does this
<p:panel ...>
<f:facet name="footer">#{message}</f:facet>
<!-- ... -->
</p:panel>
Nor this
<p:panel ...>
<f:facet name="footer">
<h:outputText value="#{message}" rendered="#{!empty message}"/>
</f:facet>
<!-- ... -->
</p:panel>
by "works" I mean:
"renders no footer — not just an empty footer — when #{message} is empty or null; otherwise, correctly renders the footer with the specified text."
PrimeFaces forum thread on this issue
You could declare a ui:param and let the template check the param while renderring.
The facet in the template could then be declared as:
<f:facet name="#{hideFooter == null or not hideFooter ? 'footer' : ''}">
#{message}
</f:facet>
Any page can then declare this param
<ui:param name='hideFooter' value='#{some rule}' />
and set the appropriate rule for the param. For any page that does not declare the param, the footer will be displayed.
Here's what I did in trying to conditionally render a facet within a composite component.
<composite:interface>
<composite:facet name="header" required="false" />
</composite:interface>
<composite:implementation>
<p:panel>
<c:if test="#{empty component.facets.header}" >
<f:facet id="#{cc.attrs.id}_default_header" name="header">
all sorts of stuff here
</f:facet>
</c:if>
<c:if test="#{not empty component.facets.header}">
<composite:insertFacet id="#{cc.attrs.id}_custom_header" name="header" />
</c:if>
<composite:insertChildren id="#{cc.attrs.id}_content"/>
</p:panel>
</composite:implementation>
This let's the user of the composite component supply the header facet if they want, and if they don't, we supply a default. Obviously, instead of providing a default, you could simply not do anything.
This mixes c:if in jsf controls, but we didn't see any adverse effects.
I have come across a similar issue with plain JSF. I am not sure how a <p:panel> is rendered, but if it is rendered as a table, you can try this:
First, declare a CSS-class like this:
.HideFooter tfoot {
display: none;
}
Then set that class conditionally on the panel:
<p:panel styleClass="#{renderFooterCondition ? null : 'HideFooter'}">
The footer is still rendered in the JSF-sense, but it is not displayed and does not take up any space in the page when viewed by the user-agent.
I successfully solved this problem using ui:fragment
<ui:fragment rendered="...Test...">
<f:facet name="footer">
...
</f:facet>
</ui:fragment>
works for example to conditionnaly render the footer of a primefaces datatable (the rendered attribute of the facet does not work).
Not sure how well this would work for your footer, but I had the same issue with a legend I was trying to conditionally render. I fixed it by using the rendered on anything inside the facet tag.
<p:fieldset>
<f:facet name="legend">
<h:outputText value="#{header1}" rendered="#{header1.exists}"/>
<h:outputText value="#{header2}" rendered="#{not header1.exists}"/>
</f:facet>
content
</p:fieldset>
I had difficulty trying c:if with my ui:repeat, so this was my solution. Not quite the same as your problem, but similar.
Facets are not intended to render HTML, which is why it doesn't have the rendered attribute. Facets add functionality to a page. The term facet is probably a poor choice of name. It's very ambiguous.
..if the list compiled by ITworld's Phil Johnson has it right, the
single hardest thing developers do is name things.
ie.
JSF facets
A project facet is a specific unit of functionality that you can add to a project when that functionality is required. When a project facet is added to a project, it can add natures, builders, classpath entries, and resources to a project, depending on the characteristics of the particular project. JSF facets define the characteristics of your JSF enabled web application. The JSF facets specify the requirements and constraints that apply to your JSF project.
The JSF facets supply a set behaviors and capabilities to your web application.
This is a counter-answer to the answer from Ludovic Pénet.
This worked for me in <f:facet name="footer"> in selected p:column items of a p:dataTable (Primefaces 5.3):
...
Note how I have the ui:fragment inside the f:facet, not outside (not wrapping) it. It definitely completely removes the entire row when every footer facet is tested to NOT render (as far as I can tell, independent of the content within the ui:fragment).
Try with this, from primefaces web page
<p:columnGroup type="footer">
<p:row>
<p:column colspan="3" style="text-align:right" footerText="Totals:" />
<p:column footerText="your value in ajax" />
<p:column footerText="your value in ajax" />
</p:row>
</p:columnGroup>
clik here, to view primefaces' webpage
For those who landed here trying to hide the footer, instead of header, but the syntax component.facets.footer didn't work, should try this:
<p:panel id="panelContent">
<c:if test="#{not empty cc.facets.footer}">
<f:facet name="footer" height="100%">
your content
</f:facet>
</c:if>
</panel>
Why don't you enclose the content of the footer into a panelGroup which has the rendered attribute?
This way:
<p:panel header="some text">
<f:facet name="footer">
<h:panelGroup rendered="#{!empty message}">
#{message}
</h:panelGroup>
</f:facet>
<!-- ... -->
</p:panel>
I do it in my weapp and it works, no footer is rendered.
I don't use primefaces though, I do it with h:datatable, but I think that it must works with p:panel too.
I try this solution and ok. (http://www.coderanch.com/t/431222/JSF/java/dynamically-set-panel-header-condition)
<rich:dataGrid value="#{myMB.student.list}" rendered="#{!empty myMB.student and !empty myMB.student.list}" var="st" rowKeyVar="row">
<rich:panel>
<f:facet name="header">
<h:panelGroup id="panelHeader">
<h:outputText value="Just one student" id="header1" required="true" rendered="#{!myMB.manyStudents}"/>
<h:outputText value="#{row+1}º Student" id="header2" required="true" rendered="#{myMB.manyStudents}"/>
</h:panelGroup>
</f:facet>
<rich:panel>

Resources