Rendering of an element depending on primefaces rating - jsf-2

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?

Related

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

can't refresh a selectOneMenu

first excuse my english if it's not correct ...
I've a probleme with a primeface's component, I'm trying to refresh a p:selectOneMenu from a p:commandButton, but it's doesn't work (it 's work on another xhtml page, but not here and I can't understand why ...)
First I select an item from an p:autocomplete which update a backingbean's attribute ( for example : userChoose ).
then the p:commandButton is able to call his listener and add userChoose to a list, but i can't refresh the selectOneMenu that display the list. I have to use another p:commandButton to refresh the list.
My form is included into a p:tabMenu in another xhtml page.
<p:autoComplete id="acPojo" value="#{forumBean.user}"
completeMethod="#{autoCompleteBean.completeUser}"
converter="#{userConverter}" forceSelection="true"
var="usr" itemLabel="#{usr.loginUtilisateur}" itemValue="#{usr}">
<p:column>
<h:outputText value="#{usr.loginUtilisateur}"/>
</p:column>
</p:autoComplete>
<p:commandButton value="ajouter" process="acPojo #this "
udpate=":tabView:formSujet:listeUser" actionListener="#{forumBean.addUser}"/>
<p:selectOneMenu value="#{forumBean.user}" converter="#{userConverter}" var="us" id="listeUser"
itemValue="#{us}" itemLabel="#{us.loginUtilisateur}">
<f:selectItems value="#{forumBean.newSujet.listeUserAllowed}" var="User"
itemValue="#{User}" itemLabel="#{User.loginUtilisateur}" />
<p:column>
<h:outputText value="#{us.loginUtilisateur}"/>
</p:column>
<p:ajax process="#this" />
</p:selectOneMenu>
<p:commandButton id="refreshAdmin" icon="ui-icon-arrowrefresh-1-w"
update=":tabView:formSujet:listeUser" />
Thanks for help.
From your code:
udpate=":tabView:formSujet:listeUser"
This has at least 2 (potential) mistakes. The right attribute name is update, not udpate. The one on your other button has however the right attribute name.
It that still doesn't work, then the other potential mistake is that the client ID tabView:formSujet:listeUser does not exist in HTML DOM tree (and thus JavaScript/jQuery is unable to find and replace it). That can happen if the <p:tabView> is dynamic (i.e. you're using <p:tabView value="#{bean.tabs}" var="tab">, because it prepents the tab index number in the final client ID like so tabView:0:formSujet:listeUser if it's the 1st tab.
But, after all, as both the dropdownlist and the commandbutton are in the same NamingContainer parent, you don't need an absolute client ID at all. Just the relative client ID should suffice:
update="listeUser"
Fix that on your both buttons.
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"

Constructor of a viewScoped class invoked twice

I've been struggling with this for two days with no success and I think it's already time to ask for your help. But first of all, this is what I'm using:
JSF 2 Mojara 2.1.1
Primefaces 3.4.2
Netbeans 7.1.1
Tomcat 7.0.37
And now, the problem: I have a main page which is composed by several other pages using several <ui:include .. /> tags, like this:
<ui:composition template="/resources/templates/template1.xhtml">
<ui:define name="appData">
<p:panelGrid columns="1" id="contenidoAplicacion" styleClass="noborder">
<h:form id="fNewPerson">
<p:panel header="New employee" style="min-height:40em">
<ui:include src="./forms/personal.xhtml" />
<p:accordionPanel styleClass="noborder" activeIndex="3">
<p:tab id="tabSomeData" title="Identidad profesional" >
<ui:include src="./forms/formSomeData.xhtml" />
</p:tab>
....
....
</ui:define>
</ui:composition>
The personal.xhtm file looks like this:
<p:panelGrid>
<p:row>
<p:column >
<h:outputLabel value="Field1"/>
<p:inputText label="Field1" id="field1" value="#{dataBacking.selectedPerson.field1}" tabindex="1"
required="true" size="10" >
<f:convertNumber for="field1" integerOnly="true" groupingUsed="false"/>
</p:inputText>
<p:inputText id="field2" value="#{dataBacking.selectedPerson.field2}" tabindex="2" required="true" size="1" maxlength="1" >
<p:ajax event="keyup" listener="#{dataBacking.check}"
process="field1 field2" partialSubmit="true"
update="field1 field2 photo"/>
</p:inputText>
</p:column>
<p:column rowspan="5" >
<p:graphicImage id="photo" value="#{dataBacking.selectedPerson.photo}" width="90" />
</p:column>
</p:row>
...
</p:panelGrid>
The check() method in the dataBacking class is irrelevant because it only checks if the field1 and the field2 meet some rules and it works properly. The problem comes when the main page is loaded for the first time. In that case, the <p:ajax /> component in personal.xhtml doesn't work. I have to reload the page (simply by pressing the F5 key) and this time it works as it would be expected.
I've been changing some attributes of the component, but nothing seems to work. I really don't know what else to do. Any kind of help will be apreciated.
EDITED. After one more day, I think the problem has nothing to do with Primefaces ajax component, as the title of the question suggested. I've come to this conclusion through these two facts:
The behaviour with the <f:ajax .../> component remains the same.
I've figured out that the view relative to the first time I load the page is not persisted. I'll try to explain myself.
The DataBacking class has defined its scope as view so that the page can "see" all the attributes and methods during the time it's been shown to the user. However, I've noticed that the constructor is called twice: the first time the page is loaded (and then, none of the methods of the class are successfully invoked) and when I refresh the page. In this last case, the behaviour of both the page and the class is the expected one.

Getting the filtered list in datatable

I am trying to filter a datatable using filter field in the column and get the filtered list (which populates datatable) and update another component (Toplam TL Teminati and Toplam Dolar Teminati) according to the filtered list's values in my page.
Is there anyway to do this in Primefaces 2.2.1 and JSF 2? If not can you rec commend a workaround for this case?
Thanks in advance.
To give you an example of how I achieved custom filter logic in my Primefaces 2.2.1 dataTable, I am giving you a scaled version of my code.
<p:dataTable value="#{listBeans.beans}" var="bean" dynamic="true" paginator="true" rows="20" paginatorPosition="bottom"
emptyMessage="No Beans" loadingMessage="Loading. . ." selectionMode="single" selection="#{listBeans.selectedBean}"
id="beanList" widgetVar="beanTable">
<f:facet name="header">
<h:panelGrid columns="4">
<h:outputText value="Bean List" />
<p:outputPanel>
<h:outputText value="Year Filter: " />
<h:selectOneMenu value="#{listBeans.yearFilter}"
onchange="yearFilterBtn.jq.click(); refreshFilters();">
<f:selectItems value="#{listBeans.years}" />
</h:selectOneMenu>
<p:commandButton id="yearFilterBtn" widgetVar="yearFilterBtn" action="#{listBeans.filterYears}"
update="listBeansForm:beanList" style="display:none;" />
</p:outputPanel>
<p:outputPanel>
<h:outputText value="Filter By Beanchild: " />
<p:inputText value="#{listBeans.beanchildFilter}" style="width: 150px; margin-right: 4px;" />
<!-- refreshFilters forces the visitor filter to refresh the selection if column filters are selected. -->
<p:commandButton oncomplete="refreshFilters();" value="Filter"
action="#{listBeans.filterBeanchildren}" update="listBeansForm:beanList" />
</p:outputPanel>
<p:commandButton value="Export to XLS" ajax="false">
<p:dataExporter target="beanList" type="xls" fileName="BeanReport"
excludeColumns="0,5,6" postProcessor="#{listBeans.postProcessExcelReport}" />
</p:commandButton>
</h:panelGrid>
</f:facet>
<p:column style="width:16px">
<p:rowToggler />
</p:column>
<p:column filterStyleClass="filtertag" filterBy="#{bean.beanDateDisplay}" filterMatchMode="startsWith">
....
</p:dataTable>
Without really going into too much detail about the managed bean code, the actions of the command button are essentially passing filter arguments to my BO layer that requery the database for the new list of beans. The explicit update of the dataTable component is needed to refresh the data.
You will notice that on the explicit Beanchild Filter button that is not hidden, I have an oncomplete attribute that references a javascript function called refreshFilters(). I can't remember exactly the problem I had, but I think it is a bug in the 2.2.1 version of Primefaces when a column filter value exists and an asynchronous update occurs within the dataTable itself. Here is the javascript function:
function refreshFilters() {
var filters = jQuery('.filtertag');
var uppedOnce = false;
filters.each(function(idx) {
var curEl = jQuery(this);
if (curEl.val() != '') {
curEl.keyup();
uppedOnce = true;
}
});
if (!uppedOnce) {
jQuery(filters[0]).keyup();
}
}
You can see here that I am locating every DOM element that has the class filtertag, which would be the column filters. I am saying that if a value exists in that field after the server action is complete, then I am manually triggering a keyup event as this will "refilter" the column with the previous value from before.
I am not sure if it is necessary in later versions of Primefaces, I am not even sure it is necessary now, so I suggest trying to do this without the Javascript workaround and if you run into problems cooridnating the two then you can consider using the Javascript.

Resources