h:selectManyCheckbox with POJO problem - jsf-2

I tried some ways to achieve this simple thing :
Show a collection of POJOs in form of checkboxes
When i click on one of the checkboxes, a method should be executed
The method will be able to access the pojo/checkbox that was clicked
I tried to implement it this way :
<h:selectManyCheckbox id="groupUsers" layout="pageDirection" value="#{timetableBean.selectedUsers}">
<f:ajax listener="#{timetableBean.processUserEvents}" render="#this" />
<f:selectItems value="#{timetableBean.group.users}"
var="user" itemLabel="#{user.userId} - #{user.name}" itemValue="#{user}">
<f:attribute name="user" value="#{user}" />
</f:selectItems>
</h:selectManyCheckbox>
And my method is :
public void processUserEvents(AjaxBehaviorEvent e) {
User user = (User) e.getComponent().getAttributes().get("user");
...
}
The user fetched from e.getComponent().getAttributes().get("user"); is sadly null
In what way can i accomplish this ?
Thank you !

Related

JSF getRowData on nested element in data table

I'm working on an application in JSF to manage trips made by the people in the various offices in my company.
(i'll try to keep the code at the minimum necessary)
I have an object Trip, an object Office, and a helper object OfficeWithTrips:
public class Trip {
private BigDecimal id;
private BigDecimal officeId;
// getters and setters
}
public class OfficeWithTrips {
private Office office;
private DataModel<Trip> trips;
// getters and setters
}
The application has two pages: one where each manager sees the offices he has to manage and the trips of each office, and another with the detail of a single trip.
I have a session bean that contains the list of offices with their trips:
public class TripsListBean implements Serializable {
private DataModel<OfficeWithTrips> officesWithTrips;
private Trip currentTrip = new Trip();
// getters and setters
}
On the main page I go through the "offices" in the bean, which has a nested list of Trips. Each office table with its list of trips has a footer with an "add new trip" button.
<h:dataTable value="#{tripsListBean.officesWithTrips}" var="officeWithTrips">
<h:column>
<h:form id="tripForm">
<h:dataTable value="#{officeWithTrips.trips}" var="trip">
<f:facet name="header">
<h:panelGrid columns="2">
<h:outputText value="Trips for the office: " />
<h:outputText value="#{officeWithTrips.office.name}" />
</h:panelGrid>
</f:facet>
<f:facet name="footer">
<h:commandButton value="Add new trip"
action="#{tripsHandler.addTrip}" />
</f:facet>
<h:column>
<f:facet name="header">Trip date</f:facet>
<h:outputText value="#{trip.date}">
<f:convertDateTime type="date" pattern="dd.MM.yyyy" />
</h:outputText>
</h:column>
// other columns
<h:column>
<h:commandButton value="edit"
action="#{tripsHandler.editTrip}">
<f:setPropertyActionListener target="#{tripsHandler.currentTrip}"
value="#{trip}" />
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
</h:column>
</h:dataTable>
When I click "add new trip" I want to be able to set the office id in the trip. What I do in "addTrip()" method is this:
public String addTrip() {
OfficeWithTrips officeWithTrips = tripsListBean.getOfficesWithTrips().getRowData();
Trip trip = new Trip();
trip.setOfficeId(officeWithTrips.getOffice.getId());
tripsListBean.setCurrentTrip(trip);
return TRIP_DETAIL_URL;
}
My problem is that in addTrip the index in officesWithTrips is always 0, when I want to add a trip to the second office in the list it doesn't work (it always returns the first office).
Can anyone spot the error? I guess that when I click the "add new trip" button, this sets the index in the officeWithTrips.trips dataModel, but not in tripsListBean.officesWithTrips...
I solved this with another setPropertyActionListener: I added an Office currentOffice to TripsListBean and set that with a setPropertyActionListener directly on the jsf page. Basically, the same I do for currentTrip

Updating data operation in JSF

I'm much newbie to the JSF. I am creating a simple crud app. I have done adding, and deleting but there is some problem with updating data..... when edit is clicked, bean is populated with values of whom i want to update. but it is not shown in the next page, in which it is to be edited......
this is the link which leads to editPage
<h:column>
<f:facet name="header">Edit</f:facet>
<h:form>
<h:commandLink value="Edit" action="#{personManipulate.editPerson(person)}"/>
</h:form>
</h:column>
this is the code which assign person data to person entity
public String editPerson(PersonEntity person){
this.person=person;
return "success2";
}
This is the code which updates per save person
public String savePerson(){
if(person.getPersonId() > 0){
personDao.updatePerson(person);
return "success";
}else{
personDao.addPerson(person);
return "success";
}
}
}
This is the page where values should be shown and Updated
<h:form>
<h:panelGrid columns="2">
<f:facet name="header">Person</f:facet>
<h:outputLabel for="firstName" value="First name" />
<h:inputText id="firstName" value="#{personManipulate.person.firstName}"
label="First name" />
<h:outputLabel for="lastName" value="Last name" />
<h:inputText id="lastName" value="#{personManipulate.person.lastName}"
label="Last name" />
<h:outputLabel for="address" value="Address" />
<h:inputText id="address" value="#{personManipulate.person.address}"
label="Address" />
<h:outputLabel for="phone" value="Contact Number" />
<h:inputText id="phone" value="#{personManipulate.person.phone}" />
<h:commandButton action="#{personManipulate.savePerson}" value="Submit" />
<h:button outcome="ShowPersons.xhtml" value="Cancel" />
</h:panelGrid>
</h:form>
This is the navigation rule
<navigation-rule>
<from-view-id>JSF/personManipulate.xhtml</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>JSF/ShowPersons.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>JSF/ShowPersons.xhtml</from-view-id>
<navigation-case>
<from-outcome>success2</from-outcome>
<to-view-id>JSF/personManipulate.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
On Debugging everything is fine i.e. data is assigned to person object but not shown on update page
Well, you're trying to access the #{personManipulate} bean, which still has not been created when you're in the people list. Supposing it is a #ViewScoped bean as it should, that should be created when you address to JSF/personManipulate.xhtml specifically. So I would encourage you to do the People List -> Edit Person transition using a GET request, instead:
showPersons.xhtml
<h:column>
<f:facet name="header">Edit</f:facet>
<h:form>
<h:link value="Edit" outcome="personManipulate.xhtml">
<f:param name="idPerson" value="#{person.id}" />
</h:link>
</h:form>
</h:column>
That will direct you to an url similar as: personManipulate.xhtml?idPerson=1. Then, load the person before the #{personManipulate} bean makes the rendering task:
personManipulate.xhtml
<f:metadata>
<f:viewParam name="idPerson" value="#{personManipulate.idPerson}" />
<f:event listener="#{personManipulate.loadData}" type="preRenderView" />
</f:metadata>
PersonManipulate.java
public void loadData(ComponentSystemEvent event){
person = service.getPersonById(idPerson);
}
That way you keep both view beans unbound and you use urls for navigation. If you aren't interested in showing the person id in the url, then you can use the Flash scope to pass it from bean to bean. Have a look at the linked posts.
See also:
View parameter when navigating to another page
Understand Flash Scope in JSF2

Want to show a data table populated with data after a button click

I want to write a code in this way, that If I click on a button a data table appears populated with data. before that there should not be the data table in view.
<p:commandButton value="Go" styleClass="apply_button" actionListener="#{searchBean.getUserList}">
<f:attribute name="trigram" value="#{searchBean.trigram}"/>
<f:attribute name="firstName" value="#{searchBean.firstName}"/>
<f:attribute name="lastName" value="#{searchBean.lastName}"/>
</p:commandButton>
here the method getUserList() returns a list of data that should be populated in the data table.and it works.
<p:dataTable value="#{searchBean.listUser}" var="user">
<p:column headerText="Trigram">
<h:outputText value="#{searchBean.trigram}"/>
</p:column>
</p:dataTable>
It shows in the Data Table after I click on the button, But the Data Table appears before the button click with empty fields. How can I modify my codes to show make the Data Table appear after my button click?
Codes are within the <h:form> Tag.
And the Managed Bean searchBean is in #ViewScoped.
You can initialize a simple getter/setter :
private boolean visible = false; // getter/setter
public void getUserList(ActionEvent event)
{
setVisible(true);
// Your code
}
And modify your view like this :
<p:commandButton value="Go" styleClass="apply_button" actionListener="#{searchBean.getUserList}" update="table-wrapper">
<f:attribute name="trigram" value="#{searchBean.trigram}"/>
<f:attribute name="firstName" value="#{searchBean.firstName}"/>
<f:attribute name="lastName" value="#{searchBean.lastName}"/>
</p:commandButton>
<h:panelGroup id="table-wrapper">
<p:dataTable rendered="#{searchBean.visible}" value="#{searchBean.listUser}" var="user">
<p:column headerText="Trigram">
<h:outputText value="#{searchBean.trigram}"/>
</p:column>
</p:dataTable>
</h:panelGroup>
Note the update attribute on button, h:panelGroup wrapper and rendered attribute on table.

display growl when page is loaded primefaces jsf2

I have this commandButton :
<p:commandButton value="Enregistrer" action="#{reglementClientMB.ajouter}"
process="#this #form" update="#form" >
<f:setPropertyActionListener target="#{reglementClientMB.est_ajouter}" value="false" />
</p:commandButton>
the action method return to another page , I want to display one p:growl when the next page is loaded
I tested to put that is the constructor of its managed bean but the growl is displayed below data in the page
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_INFO, ""
+ "Confirmation", "Réglement crée avec sucée"));
RequestContext.getCurrentInstance().update("messages");
how can I achieve this
thank you in advance
The bean's constructor may be too late for the job if the <p:growl> is rendered before the bean is been constructed for the first time. E.g.
<p:growl />
...
<h:outputText value="#{bean.something}" />
It would only work if the bean is constructed before the <p:growl> is rendered.
<h:outputText value="#{bean.something}" />
...
<p:growl />
In order to solve your concrete problem, you'd need to do the job in a pre render view listener instead.
<f:event type="preRenderView" listener="#{bean.init}" />
With:
public void init() {
// Add the desired message here.
}

primefaces autocomplete when cleared field giving previuos results of page on clicking submit button

I am using an autocomplete tag of prime faces which retrieves results from a database.
The problem is that when I submit the form leaving the autocomplete field empty the results I get on the page are those of the previous request (the previously selected autocomplete value) - it only gets cleared when I refresh the page.
I want that on each submit, without refreshing the browser page, if i clear out the value in the field using backspaces and submit the form it should give the correct result for this particular instance, not previous one.
I am also using some textfields in the jsf page form but those don't have this problem.
Can anyone offer guidance as to how this problem can be corrected?
EDITED:
Code:
<h:form>
<h:dataTable id="Ressult" value="#{input.searchResults}" var="r">
<h:column>#{r.ID}</h:column>
<h:column>#{r.Name}</h:column>
</h:dataTable>
<tr>
<td>Current Education Level</td>
<td>
<h:panelGrid styleClass="text-box">
<p:autoComplete id="education" value="#{input.education}"
completeMethod="#{input.getautocomplete}" var="a"
itemLabel="#{a.Name}" itemValue="#{a}"
converter="edConverter" forceSelection="true" />
<p:column>#{a.Name} - #{a.id}</p:column>
</h:panelGrid>
</td>
</tr>
<tr>
<td>City</td>
<td>
<h:selectOneMenu id="txtCity" styleClass="select-field"
value="#{input.cityId}">
<f:selectItem itemLabel=" Please Select" itemValue="0">
</f:selectItem>
<f:selectItems value="#{input.cities}"></f:selectItems>
</h:selectOneMenu>
</td>
</tr>
<tr>
<td>Name of Person</td>
<td>
<h:inputText id="txtName" value="#{input.nameOfPerson}"
styleClass="text-box"></h:inputText>
</td>
</tr>
<h:commandButton id="btnSearch" value="Search"
action="#{input.searching}">
<f:ajax execute="#form" render="Ressult"></f:ajax>
</h:commandButton>
</h:form>
And here is the bean code:
public class Input
{
private Education education;
private List<SelectItem> cities;
private Integer cityId;
private String nameOfPerson;
private List<Results> searchResults;
//getters and setters
public String searching()
{
searchResults=dao.getSearchResults(cityId,education,nameOfPerson);
return "success";
}
public void autocomplete(String query)
{
//AUTOCOMPLTE lIST CODE HERE
}
}
By update, if you mean new results to be shown when new items selected, then yes - the form should be updated but autocomplete somehow takes the previously selected value and shows results according to that. At least until I refresh the page - only then is autocomplete's previous is removed.
I had the same problem with my autocomplete widget.
When I removed its id attribute it worked. Maybe a bug in Primefaces.
You may have two things to do:
Prevent the user from submission by pressing the Enter key by doing the following in your form:
<h:form onkeypress="return event.keyCode != 13;">
Using itemSelect/itemUnselect features provided to empty the field in the Bean:
<p:ajax event="itemSelect"
listener="#{autoCompleteBean.handleSelect}" global="false"
update=":some:where" />
<p:ajax event="itemUnselect"
listener="#{autoCompleteBean.handleUnselect}" global="false"
update=":some:where" />
<!-- rest of your facelet stuff -->
In the Bean:
public void handleSelect(final SelectEvent event) {
final Search search = (Search) event.getObject();
// do your addition here
}
public void handleUnselect(final UnselectEvent event) {
final Search search = (Search) event.getObject();
// do your substraction here
}
Well if i understand your question correctly your list of auto completion is shown after the post. And you use your form to submit time after time to the same page.
Your bean looks a little bit odd. Because you're calling in the page the autocomplete method: getautocomplete but that one doesn't exists in your bean.
Use the autocomplete in this way:
<p:autoComplete id="education" value="#{input.education}" completeMethod="#{input.autocomplete}" var="a" itemLabel="#{a.Name}" itemValue="#{a}" converter="edConverter" forceSelection="true" />
And in your bean:
public List<Education> autocomplete(String query)
{
List<Education> educations = new ArrayList<Education>();
//search with query in your dao something like:
educations = dao.searchEducation(query);
return educations;
}
fixed on 5.2, upgrade your primefaces jar
here the log issue
https://code.google.com/p/primefaces/issues/detail?id=7592
To fix the subject issue you just remove the forceselection
or make it as false.
Just process event to server. Works with forceselection="true"
<p:ajax event="itemUnselect" global="false" />

Resources