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
Related
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
Based on this subject, I would like to update a <p:overlayPanel> from a datatable to a composite component
View
<h:form id="myForm">
<p:dataTable id="myTable" ...>
<p:column headerText="1">
<p:commandLink id="link"
actionListener="#{bean.update}"
update=":toto" value="Val" />
<p:overlayPanel id="panel" for="link">
<my:view id="toto">
</p:overlayPanel>
</p:column>
</p:dataTable>
</h:form>
Composite
<composite:implementation>
<span id="#{cc.clientId}">
<p:dataTable id="toto" ...>
</p:dataTable>
</span>
</composite:implementation>
However I always get an error message saying that :toto component id can not be reached.
So, how can I access the dataTable placed in the composite ?
EDIT : Actually I changed my mind concerning the utilisation of p:overlayPanel for a p:datatable because of the creation of dynamic ids. I replaced this by a p:dialog and it works great.
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.
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.
}
I have programmed a little application in which you can register and edit your data. For the authenticity I used a bean class called Authenticity. This class contains an object of Customer (which is a database entity) and methods to login and to logout.
Now I´ve created a page for editing the user: A form with many inputTexts which have the value of authenticity.curUser./(properties). It look like this:
<h:form>
<h:panelGrid columns="2" cellpadding="4px" width="600">
<h:outputText value="firstname:" />
<h:inputText value="#{authenticity.curUser.firstname}"/>
<h:outputText value="lastname:"/>
<h:inputText value="#{authenticity.curUser.lastname}" />
<h:outputText value="street:"/>
<h:inputText value="#{authenticity.curUser.street}" />
<h:outputText value="housebumber"/>
<h:inputText value="#{authenticity.curUser.housenumber}" />
<h:outputText value="Zip:"/>
<h:inputText value="#{authenticity.curUser.zip}" />
<h:outputText value="City:"/>
<h:inputText value="#{authenticity.curUser.city}" />
<h:outputText value="Land"/>
<h:inputText value="#{authenticity.curUser.country}" />
<h:outputText value="email:"/>
<h:inputText value="#{authenticity.curUser.email}" />
<h:outputText value="password:"/>
<h:inputSecret value="#{authenticity.curUser.password}" />
<h:commandButton action="#{authenticity.editUser}" value="Edit" />
</h:panelGrid>
</h:form>
My question now is whether there are better solutions for this problem. Should a AuthenticityBean be actually able to edit the user? Or should I create a extra bean?
I would use a completely separate view scoped bean which holds a brand new copy of the entity representing the logged-in user. Only when the form is successfully edited and saved, then the currently logged-in user can be replaced (the form bean can just access it as a #ManagedProperty).
If you were reusing the same entity in the form; imagine that you're ajax-updating some fields and then cancels/closes the form. The currently logged-in user would then still have the "Wrong" field values in the remnant of the session. This is not correct.