JSF2+PF: Update dialog header when it opens or shows - jsf-2

Is there a way to update the dialog header text when it opens? I used to use the dynamic attribute and set it to true. But due to issues with Form and Bean state (the dialog has a form inside), I had to abandon its usage. There is a hook to the js attribute onShow but I'm not sure how to update the header text from there.
Here is a simplified version of what my dialog looks like. It is defined as a composite component (not shown):
<composite:interface componentType="addEditDialog">
...
</composite:interface>
<composite:implementation>
<p:dialog>
<f:facet name="header">
#{cc.headerText}
</f:facet>
....
</p:dialog>
...
</composite:implementation>
I have some custom code in the backing NamingContainer class that determines the actual header text when it is opened:
#FacesComponent("addEditDialog")
public class AddEditCompositeComponent extends UINamingContainer {
public String getHeaderText() {
....
}
}

I ended up wrapping the header text in a PF outputPanel with autoUpdate=true and it works for me.
<p:dialog>
<f:facet name="header">
<p:outputPanel autoUpdate="true">#{cc.headerText}</p:outputPanel>
</f:facet>
....
</p:dialog>

Related

Rendering of an element depending on primefaces rating

I started using primafaces and I came up with the following scenario. The user rates and element and if the rating is valid then a span block appears or it hides depending the case. I am based on the example here: (http://www.primefaces.org/showcase/ui/input/rating.xhtml ) with the ajax approach. Note that a rate is valid if the user clicks on any star. So here's what I've done so far:
<h:form>
<p:panelGrid>
<p:row>
<p:column>
<p:rating value="#{searchBean.dateWeight}">
<p:ajax event="rate" listener="#{searchBean.addDatetoWeights}"
update="dates" render="dates" />
<p:ajax event="cancel"
listener="#{searchBean.removeDatefromWeights}"
update="dates" />
</p:rating>
<h:panelGroup id="dates" rendered="#{searchBean.dateRated}">
<h:outputText value="test"></h:outputText>
</h:panelGroup>
</p:column>
</p:row>
</p:panelGrid>
</h:form>
segment of the bean:
boolean dateRated;
int dateWeight;
public void addDatetoWeights(){
dateRated=true;
weights.put("date",dateWeight);
System.out.println(dateRated);
}
public void removeDatefromWeights(){
dateRated=false;
if(weights.containsKey("date"))
weights.remove("date");
}
Let's go back to the basics: HTML and JavaScript. It's important to also know them before diving into JSF. JSF is in the context of this question merely a HTML/JS code generator.
With <p:ajax update="dates"> you're basically telling JavaScript to grab the HTML element by the given ID and then replace its contents with the new contents retrieved from server in ajax response. However, as the <h:panelGroup id="dates"> is in first place never rendered to the HTML output, JavaScript can't find the element by document.getElementById() stuff in order to replace its contents and then just ignores the instruction.
Instead, the <p:ajax update="dates"> must refer a component which is always rendered, so that JavaScript can actually find it. Only its contents can be conditionally rendered.
Here's a rewrite:
<h:panelGroup id="dates">
<h:outputText value="test" rendered="#{searchBean.dateRated}" />
</h:panelGroup>
See also:
Why do I need to nest a component with rendered="#{some}" in another component when I want to ajax-update it?

JSF command button updating even there are validation errors

I'm new to JSF, my question may be silly for you.. It is very much valuable for me..
<h:form id="form1">
<p:messages autoUpdate="true" showDetails="true" />
<p:dataTable id='form1ID'>....</dataTable>
<p:inputText value="#{bean.name}" required="true"
requiredMessage="Please Enter Name!" label="Name ">
</p:inputText>
</h:form>
<h:form id="form2">
<p:messages autoUpdate="true" showDetails="true" />
<p:dataTable id='form2ID'>....</dataTable>
<p:inputText value="#{bean.name}" required="true"
requiredMessage="Please Enter Name!" label="Name ">
</p:inputText>
<p:commandButton value="Submit" update=":form1:form1ID"
actionListener="#{mgmtBean.doCreateType}" />
</h:form>
I have two forms. when I click on form2 command button with empty fields, it will show error messages perfectly since i have added <p:messages autoUpdate="true" showDetail="true"/>.
The bad thing or surprising thing here for me is, it is showing error messages on top of form1 also may be because of <p:messages autoUpdate="true" showDetail="true"/> added in form1 and i'm trying to update form1 on command button click in form2.
I don't want to show error messages on form1 when form2 is throwing validation error messages. How can i fix this ? I googled it out.. but couldn't find the solution.
Evironment i'm using is jsf-api-2.1.5 and primefaces 4.0 version and view technology is facelets(XHTML)
Hope it is clear..
Any idea is highly appreciated.
Try to disable rendering of messages on the form1:
<p:messages autoUpdate="true" showDetails="true" rendered="#{bean.renderedmessage}"/>
And in the bean, add the renderedmessage variable:
public Boolean getRenderedmessage() {
return renderedmessage;
}
/**
* #param renderedmessage the renderedmessage to set
*/
public void setRenderedmessage(Boolean renderedmessage) {
this.renderedmessage = renderedmessage;
}
And, for the doCreateType() method, add:
public void doCreateType(){
..............
setRenderedmessage(false);
.............
}
After the form1 is updated, you can choose some event or method, where you can setRenderedmessage(true);
What you're currently experiencing should indicate to you that you usually don't need two <p:messages/>s in the same JSF view; one is enough.
Regardless of the fact that you have two <h:form/>s on your page, there's still only one FacesContext associated with that view (The FacesContext object is a JSF construct that encapsulates all the information/data/components etc that's associated with a given JSF page request).
By default the <p:messages/> will display every FacesMessage that is queued within it's associated instance of FacesContext, regardless of the source of the message (well, almost: if you set globalOnly="true" on the <p:messages/>, you can change that behaviour).
That being said, you basically have two options:
Get rid of the extra <p:messages/> and rely on (and appropriately position) only one to display all errors/warnings for that view
Specify the for attribute, set to the desired component. Doing so, you'll guarantee that only one input component can trigger the display of its associated message component. For example
<h:form id="form1">
<p:messages for="inputName" autoUpdate="true" showDetails="true" />
<p:dataTable id='form1ID'>....</dataTable>
<p:inputText id="inputName" value="#{bean.name}" required="true"
requiredMessage="Please Enter Name!" label="Name ">
</p:inputText>
</h:form>
Note that I've set an id attribute on the <p:inputText/> component; this is necessary so you can use it in the for attribute for the messages component.
Further reading:
What is FacesContext used for?
I have fixed the issue by using the following code
<p:messages autoUpdate="true" showDetails="true" visibility="info"/>
so it is just displaying info messages and other pop up error messages will not be showun.

Primefaces commandButton inside dialog not firing backing bean's method

I've just started learning JSF and PrimeFaces, and as soon as I solve a problem (with your help), another one arises. I have a datatable showing some data about my application's users; in the last column, a commandButton invokes a dialog allowing the corresponding data to be edited. The dialog actually interacts with the backing bean, since the fields are correctly precompiled with the existing data, but the "Submit changes" commandButton doesn't fire the proper editUser() method!
I've searched everywhere for a solution to my problem, but none of the threads on the PrimeFaces forums nor any question here on Stack Overflow helped me: I tried all combinations of action, actionListener, inner <h:form>, outer <h:form>, even the dreaded nested <h:form>, but the underlying method is still not called.
Thank you all, people!
EDIT: I included some more xhtml. Just to be clear: in the datatable I'm implementing both single and multiple selection mechanisms. The single selection is performed by the editButton in the last column and triggers the editDialog that's giving me pain, while multiple selection is enabled by the checkboxes in the first column and is targeted by a commandButton at the bottom of the table that deletes all selected users; of course they store the selections in different fields in the backing bean (selectedUser and selectedUsers[], respectively).
xhtml file
<h:form id="tableForm">
<p:dataTable id="userList" var="user" value="#{userListBean.userList}"
selection="#{userListBean.selectedUsers}" rowKey="#{user.username}">
<!-- this is a checkbox column I use for multiple selection -->
<p:column selectionMode="multiple" style="width:2%"/>
<!-- other datatable columns -->
<!-- this is the button column that triggers the dialog -->
<p:column style="width:4%">
<p:commandButton id="editButton" update=":tableForm:editUserData"
oncomplete="PF('editDialog').show()" title="Edit" icon="ui-icon-pencil">
<f:setPropertyActionListener target="#{userListBean.selectedUser}"
value="#{user}" />
</p:commandButton>
</p:column>
</p:datatable>
<p:dialog id="editDlg" widgetVar="editDialog" header="Edit User"
showEffect="fade" hideEffect="fade" modal="true" dynamic="true">
<h:panelGrid columns="6" id="editUserData">
<p:outputLabel for="editUsername">Username:</p:outputLabel>
<p:inputText disabled="true" id="editUsername" value="#{userListBean.selectedUser.username}" />
<p:message for="editUsername" />
<!-- and other fields like that -->
</h:panelGrid>
<p:commandButton id="submitChanges" action="#{userListBean.editUser()}"
value="Submit changes" oncomplete="PF('editDialog').hide();" />
</p:dialog>
</h:form>
Backing bean
#ManagedBean(name="userListBean")
#ViewScoped
public class UserListBean {
private UserDTO selectedUser;
public UserListBean() {
}
//some methods...
public String editUser() {
System.out.println("------------------ EDIT TRIGGERED! -------------------");
System.out.println(selectedUser.getUsername());
//this stuff never gets printed, so the method is never called!
}
//getters and setters
}
Actually, the only thing didn't come to my mind turned out to be the one that worked.
I sorted out my issue by using THREE forms (as I mentioned in my question, I had already tried out all possible combinations of one and two forms, even nested ones), like this:
<h:form id="tableForm">
<!-- here lies the p:dataTable -->
</h:form>
<p:dialog>
<h:form id="dialogForm">
<!-- here lies the h:panelGrid with the editable fields -->
</h:form>
<h:form id="buttonForm">
<!-- and HERE goes the commandButton, alone -->
</h:form>
</p:dialog>
It looks like everyone solves this problem in ways that don't work for others :) .

Primefaces enum output facet updates wrong

I'm facing some problems using a primefaces cell editing table. So, I have a datatable, which contains an editable column. This datatable is populated through a list of jpa entity.
Focusing on wich matters, my editable cell, has an outputText in the output facet and a selectOneMenu in the input facet, which is populated by an enum.
My problem is that, datatable is correctly loaded at beginning, I can successfully edit the wanted field, selectOneMenu is correctly populated with enum. If I choose an option in the selectOneMenu, it gets fine, HOWEVER when I click outside the datatable (to quit editing mode), it gets a wrong value, since it gets the code, and it should get description.
My code:
Enum:
public enum EnumSimNao implements DetalheDominioEnum {
/**
* Sim
*/
S("Sim"),
/**
* Não
*/
N("Não");
Enum has a getter that refreshes the value based in some services. It always get those values from the service. I've tested it and the values are right here. When I say description, I mean "Sim" or "Nao", and the codes are respectively "S" or "N". From the database it comes a code, that is associated with enum through an #Enumerated attribute in an jpa entity. When I have #{tp.respostaObrigatoria.description} it returns me "Sim" or "Não" based on the returned code.
public String getDescription() {
DetalheEstaticoDominioEnumHelper.INSTANCE.fillDescriptions(this);
return description == null ? defaultDescription : description;
}
#Override
public void setDescription(String description) {
this.description = description;
}
xhtml:
<p:cellEditor>
<f:facet name="output">
<h:outputText
value="#{tp.respostaObrigatoria.description}" />
</f:facet>
<f:facet name="input">
<h:selectOneMenu value="#{tp.respostaObrigatoria}">
<f:selectItems value="#{Factories.enumSimNao}" var="simNao"
itemLabel="#{simNao.description}" itemValue="#{simNao}" />
</h:selectOneMenu>
</f:facet>
</p:cellEditor>
tp is an entity whcih comes from a list that comes from backing bean:
So, when I edit the cell, I can see both descriptions ("Sim" or "Nao"), but when I exit the edit mode it shows "S" or "N". Finally, if I refresh the page, it gets the correct description value I had choose.
Do you have any tip?
Thanks
Primefaces 3.5 has this bug which apparently was filed under this issue http://code.google.com/p/primefaces/issues/detail?id=6116 and solved in version 3.5.15 which is only available on Elite version. Version 4.0 seems to have this fixed.
I found a workaround for 3.5 which involves re-rendering the form enclosing the datatable which is working fine for me.
What you need to do is to use an ajax event listener inside the selectOneMenu component which triggers the render of the form like this:
<p:cellEditor>
<f:facet name="output">
<h:outputText
value="#{tp.respostaObrigatoria.description}" />
</f:facet>
<f:facet name="input">
<h:selectOneMenu value="#{tp.respostaObrigatoria}">
<f:selectItems value="#{Factories.enumSimNao}" var="simNao"
itemLabel="#{simNao.description}" itemValue="#{simNao}" />
<f:ajax listener="#{bean.submit}" render="#form" />
</h:selectOneMenu>
</f:facet>
</p:cellEditor>

Conditional cell edit in PrimeFaces datatable

I want to allow user to edit cells in data table only if some condition is met.
Initially I have tried <choose> to achieve this:
<p:dataTable var="item" value="${bean.items}" editable="true" editMode="cell">
<p:column headerText="column A">
<c:choose>
<c:when test="${item.isEditable}">
<p:cellEditor id="title">
<f:facet name="output">
<h:outputText value="#{item.title}"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{item.title}"/>
</f:facet>
</p:cellEditor>
</c:when>
<c:otherwise>
<h:outputText value="#{item.title}"/>
</c:otherwise>
</c:choose>
</p:column>
...
but it does not work. Another approach is to use rendered attribute:
<p:column headerText="column A">
<p:cellEditor rendered="${item.isEditable}">
<f:facet name="output">
<h:outputText value="#{item.title}"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{item.title}"/>
</f:facet>
</p:cellEditor>
<h:outputText value="#{item.title}" rendered="#{!item.isEditable}"/>
</p:column>
that works fine - user are able to edit only allowed cells.
But even if cell is not editable it still has ui-cell-editing class and looks like editable cell for user.
What is a correct way to apply condition to cell editing?
Thank you!
To properly learn the lesson of JSTL fail, it failed for the reason explained in the following answer: JSTL in JSF2 Facelets... makes sense? In a nutshell: #{item} isn't available at the moment JSTL runs.
Coming back to the concrete question: that style class is been inserted due to the combination editMode="cell" and the physical presence of <p:cellEditor> component in the <p:column>. The PrimeFaces datatable renderer isn't at all considering if the <p:cellEditor> is rendered or not. It just outright inserts the ui-editable-column style class which in turn triggers the ui-cell-editing style via JS/jQuery. You were looking in the right direction for the solution, JSTL which can conditionally physically add/remove JSF components in the JSF component tree, but unfortunately it won't work in this construct.
Your best bet is to post an issue report to the PrimeFaces guys whereby you ask to not only consider the physical presence of <p:cellEditor> component, but also its isRendered() outcome. Considering PrimeFaces version 3.5, that would be in line 796 of DataTableRenderer class which originally looks like this (newlines introduced for readability):
String styleClass = selectionEnabled
? DataTable.SELECTION_COLUMN_CLASS
: (column.getCellEditor() != null)
? DataTable.EDITABLE_COLUMN_CLASS
: null;
And should be modified as follows:
String styleClass = selectionEnabled
? DataTable.SELECTION_COLUMN_CLASS
: (column.getCellEditor() != null && column.getCellEditor().isRendered())
? DataTable.EDITABLE_COLUMN_CLASS
: null;
If you can't wait, in the meanwhile you could homegrow a custom renderer.
package com.example;
import org.primefaces.component.datatable.DataTableRenderer;
public class MyDataTableRenderer extends DataTableRenderer {
#Override
protected void encodeCell(FacesContext context, DataTable table, UIColumn column, String clientId, boolean selected) throws IOException {
// Copypaste here the original encodeCell() source code and make modifications where necessary.
}
}
Then, to get it to run, register it as follows in faces-config.xml:
<render-kit>
<renderer>
<description>Overrides the PrimeFaces table renderer with customized cell renderer.</description>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.DataTableRenderer</renderer-type>
<renderer-class>com.example.MyDataTableRenderer</renderer-class>
</renderer>
</render-kit>

Resources