This question already has answers here:
How to choose the right bean scope?
(2 answers)
Closed 7 years ago.
So, I am loading a list from H2 database to be shown, and it is updated with data from form on previous page. The datatable is update only once in session, after I submit form first time. If I reset tomcat server, all the data submitted in last session will be shown. I will upload all the code that I consider relevant,:
Managed bean, with the TaskList datatable:
#ManagedBean
#SessionScoped
public class TaskListController {
private List<Task> taskList;
private Task task;
#PostConstruct
private void init() {
taskList = TaskServiceDatabase.taskList();
}
public String loadFirstPage() {
return "createNewTask.xhtml";
}
public List<Task> getTaskList() {
return taskList;
}
//getters and setters
Tasklist method:
public static List<Task> taskList() {
List<Task> taskList = new ArrayList<Task>();
try {
taskList = DatabaseUtils.fetchTask();
} catch (Exception e) {
e.printStackTrace();
}
return taskList;
}
Fetch task method is communicating with database, I am fairly certain this works properly, if it is needed, I can add it.
And here is the.xhtml file:
<h:form id="form">
<p:dataTable id="taskTable" var="task" rowIndexVar="taskNumber"
value="#{taskListController.taskList}" paginator="true" rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,15">
<p:column>
<f:facet name="header">
<h:outputText value="Surname" />
</f:facet>
<h:outputText value="#{task.user.surname}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Name" />
</f:facet>
<h:outputText value="#{task.user.name}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Username" />
</f:facet>
<h:outputText value="#{task.user.username}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Project name" />
</f:facet>
<h:outputText value="#{task.project.projectName}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Company name" />
</f:facet>
<h:outputText value="#{task.project.companyName}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Task description" />
</f:facet>
<h:outputText value="#{task.description}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Time (h)" />
</f:facet>
<h:outputText value="#{task.time}" />
</p:column>
</p:dataTable>
<h:commandButton action="#{taskListController.loadFirstPage}"
value="Return" update="form" />
</h:form>
So, what did I do wrong?
Changing scope of bean to ViewScoped solved the issue
Related
I try to update a datatable row with PrimeFaces 3.1.1 but it makes all values null.
public void onRowEdit(RowEditEvent event) {
Client us= (Client) event.getObject();
System.out.println("event edit"+us);
clientService.editClient( us );
FacesMessage msg = new FacesMessage("Client modifié", ((Client) event.getObject()).getName_customer());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
This is my page xhtml:
<h:form>
<p:dataTable var="client" value="#{clientBean.clients}" widgetVar="clientTable" emptyMessage="No customers found with given criteria" filteredValue="#{clientBean.filteredClients}" paginator="true" rows="10" rowsPerPageTemplate="5,10,15" editable="true" id="testContainer">
<p:ajax event="rowEdit" update="#this" listener="#{clientBean.onRowEdit(event)}" />
<f:facet name="header"><p:outputPanel><h:outputText value="Recherche d'un client:" /> </p:outputPanel>
</f:facet>
<p:column filterBy="#{client.user.username}" headerText="Collaborateur" filterMatchMode="contains">
<h:outputText value="#{client.user.username}" />
</p:column>
<p:column filterBy="#{client.name_customer}" headerText="Nom" filterMatchMode="contains">
<f:facet name="output">
<h:link outcome="CustomerDetails?faces-redirect=true&includeViewParams=true" value="#{client.name_customer}" >
<f:param name="idCustomer" value="#{client.costumer_id}"></f:param>
<f:param name="nameCustomer" value="#{client.name_customer}"></f:param>
</h:link> </f:facet>
<f:facet name="input"><p:inputText value="#{client.name_customer}"/></f:facet>
</p:cellEditor>
</p:column>
<p:column filterBy="#{client.statut}" headerText="Statut" filterMatchMode="contains">
the problem is that your object Client us is null , try to display a property from your object us if is null so that will confirm that you don't get your object from your page correctly . So i suggest you to replace that :
<p:ajax event="rowEdit" update="#this" listener="#{clientBean.onRowEdit}" />
with that
<p:ajax event="rowEdit" update="#this" listener="#{clientBean.onRowEdit(event)}" />
Note that i just added the event property to onRowEdit.
I have two primefaces dataTables. The first show the instances of a MainEntity.
The second one show a list of Words (just strings) associated with the selected MainEntity on the first datatable.
The printscreen illustrates what I mean.
My problem is, when I edit a string on the Word List, my listener method won't receive the new value. In fact, when I call the event.getNewValue() method, I get old value.
What am I missing?
I'm using JavaServer Faces 2.2, Primefaces 5.0 and Spring Framework 4.0.3.
Thanks in advance for any help.
The code for the xhtml, the managed bean and the MainEntity are as follows:
mainEntity.xhtml:
<h:body>
<h:form id="mainEntityForm">
<p:panelGrid columns="1" fullPage="true" id="dashboard">
<f:facet name="header">
<h2>MainEntity Table</h2>
</f:facet>
<p:panel>
<f:facet name="header">
MainEntity List
<p:commandButton value="New MainEntity"
actionListener="#{mainEntityController.createMainEntityDialog}"
styleClass="header-button">
<p:ajax event="dialogReturn" update=":mainEntityForm:mainEntityTable" />
</p:commandButton>
</f:facet>
<p:dataTable id="mainEntityTable" var="mainEntity" value="#{mainEntityController.mainEntities}"
editable="true" editMode="cell" widgetVar="cellMainEntity"
selectionMode="single" selection="#{mainEntityController.selectedMainEntity}"
rowKey="#{mainEntity.id}" tableStyle="width:auto">
<p:ajax event="rowSelect" update=":mainEntityForm:stringGrid :mainEntityForm:entityAGrid :mainEntityForm:entityBGrid" />
<p:ajax event="cellEdit" listener="#{mainEntityController.onEditMainEntity}" update=":mainEntityForm:mainEntityTable" />
<p:column headerText="ID">
<h:outputText value="#{mainEntity.id}" />
</p:column>
<p:column headerText="Name">
<p:cellEditor>
<f:facet name="output">
<h:outputText id="nameOutput" value="#{mainEntity.name}" />
</f:facet>
<f:facet name="input">
<h:inputText id="atyInput" value="#{mainEntity.qty}" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Commands">
<p:commandButton title="Remove MainEntity" icon="ui-icon-trash"
actionListener="#{mainEntityController.deleteMainEntity(mainEntity)}"
update=":mainEntityForm:mainEntityTable" />
</p:column>
</p:dataTable>
</p:panel>
<p:panelGrid fullPage="true" id="mainEntityDetail">
<f:facet name="header">
<p:row>
<p:column colspan="4">
<h2>MainEntity Detail</h2>
</p:column>
</p:row>
</f:facet>
<p:row>
<p:column>
<p:panel>
<f:facet name="header">
Word List
<p:commandButton value="New Word"
actionListener="#{mainEntityController.addNewWord()}"
styleClass="header-button"
update=":mainEntityForm:wordGrid">
</p:commandButton>
</f:facet>
<p:dataTable id="wordGrid" var="word"
value="#{mainEntityController.selectedMainEntity.wordList}"
tableStyle="width:auto" editable="true" editMode="cell" widgetVar="cellWord">
<p:ajax event="cellEdit" listener="#{mainEntityController.onEditWord}" />
<p:column headerText="Word">
<p:cellEditor>
<f:facet name="output">
<h:outputText id="wordOutput" value="#{word}" />
</f:facet>
<f:facet name="input">
<h:inputText id="wordInput" value="#{word}" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Commands">
<p:commandButton title="Remove Word"
icon="ui-icon-trash"
actionListener="#{mainEntityController.removeWord(word)}"
update=":mainEntityForm:wordGrid" />
</p:column>
</p:dataTable>
</p:panel>
</p:column>
</p:row>
</p:panelGrid>
</p:panelGrid>
</h:form>
</h:body>
MainEntityController.java (managed bean):
#ManagedBean
#SessionScoped
public class MainEntityController {
//...
private MainEntity selectedMainEntity;
public List<MainEntity> mainEntities;
//...
public MainEntity getSelectedMainEntity(){
return selectedMainEntity;
}
public void setSelectedMainEntity(MainEntity mainEntity){
this.selectedMainEntity = mainEntity;
}
//...
public void onEditWord(CellEditEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if(newValue != null && !newValue.equals(oldValue)) {
// THE PROBLEM IS HERE
// I NEVER ACTUALLY REACH THIS CODE
// newValue is always equal to oldValue!
FacesContext context = FacesContext.getCurrentInstance();
String word = context.getApplication().evaluateExpressionGet(context, "#{word}", String.class);
System.out.println(newValue);
System.out.println(word);
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Word Changed", "Old: " + oldValue + ", New:" + newValue);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
}
MainEntity.java:
#Entity
public class MainEntity {
#Id
private String id;
#ElementCollection(fetch=FetchType.EAGER)
#CollectionTable(
name="MainEntity_Word",
joinColumns = #JoinColumn(name = "id", referencedColumnName="id")
)
#Column(name = "word")
private Set<String> wordList;
//...
public void addWord(String word) {
this.wordList.add(word);
}
public void removeWord(String word) {
this.wordList.remove(word);
}
public Set<String> getWordList() {
return wordList;
}
public void setWordList(Set<String> wordList) {
this.wordList = wordList;
}
}
Change
<h:inputText id="wordInput" value="#{word}" />
to
<p:inputText id="wordInput" value="#{word}" />
or
<h:inputText id="wordInput" value="#{word}" >
<p:ajax event="change" process="#this"/>
</h:inputText>
You need to ajaxify the input component, and at last update the outputText component.
Edited:
change this column :
<p:column headerText="Word" >
<p:cellEditor>
<f:facet name="output">
<h:outputText id="wordOutput" value="#{word}" />
</f:facet>
<f:facet name="input">
<h:inputText id="wordInput" value="#{word}" />
</f:facet>
</p:cellEditor>
</p:column>
to
<p:column headerText="Word" >
<p:cellEditor>
<f:facet name="output">
<h:outputText id="wordOutput" value="#{word}" />
</f:facet>
<f:facet name="input">
<p:inputText id="wordInput" value="#{word}" >
<p:ajax event="change" update="wordOutput" />
</p:inputText>
</f:facet>
</p:cellEditor>
</p:column>
Edit 2 :
From Chapter 24 Introduction to the Java Persistence API
If an entity instance be passed by value as a detached object, such as
through a session bean’s remote business interface, the class must
implement the Serializable interface.
I finally got it working.
I suspected of the String immutable nature and what I did was to encapsulate the 'word' in a class like the following:
public class Word {
private String word;
Word (String word) {
this.setWord(word);
}
public String getWord() {
return this.word;
}
public void setWord(String word) {
this.word = word;
}
}
After that, I also had to create a set inside the managed bean (controller) to hold the set of words, like 'private Set managedWordList;'.
I also changed the getter for the list, inside the managed bean, to convert from the String set to a Word set like:
public Set<Word> getWordList() {
if (this.selectedMainEntity != null){
this.wordList = new HashSet<Word>();
for (String word : this.selectedMainEntity.getWordList()) {
this.wordList.add(new Word(word));
}
}
return this.wordList;
}
Finally, I changed the dataTable to reference the new set. From:
<p:dataTable ... value="#{mainEntityController.selectedMainEntity.wordList}"... />
To:
<p:dataTable ... value="#{mainEntityController.wordList}"... />
And only then I got it to work as I expected.
I have been using onEdit in the p:datatable and it works fine.My data table has a pagintor and shows 5 records per page.so when I click on the onEdit in the first page event.getObject gets the changed value in the bean.Now when I go the next page the event.getObject does not work and returns the old value only.
Same with the dialog box.In the table I have a link when clicked opens a dialog box in whcih I am populating few fields with the values from the row selected.It works fine in the first page and When I navigate to other pages gives empty values.
Here is my jsf code:
<p:dataTable value="#{mybean.userList}"
var="item"
id="dataTab"
widgetVar="usersTable"
tableStyleClass="data" paginator="true" rows="5"
filteredValue="#{userController.filteredUsers}"
editable="true"
rowKey="#{item}"
>
<p:ajax event="rowEdit" listener="#{mybean.onEdit}" update=":userForm:growl" />
<p:ajax event="rowEditCancel" listener="#{mybean.onCancel}" update=":userForm:growl" />
<f:facet name="header">
<p:outputPanel>
<h:outputText value="Search all fields:" />
<p:inputText id="globalFilter" onkeyup="('usersTable').filter()" style="width:150px" />
</p:outputPanel>
</f:facet>
<p:column sortBy="#{item.firstName}" filterBy="#{item.firstName}"
filterMatchMode="startsWith">
<p:cellEditor>
<f:facet name="header">
<h:outputText value="First Name" />
</f:facet>
<f:facet name="output">
<h:outputText value="#{item.firstName}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item.firstName}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column sortBy="#{item.lastName}" filterBy="#{item.lastName}" filterMatchMode="startsWith">
<p:cellEditor>
<f:facet name="header">
<h:outputText value="Last Name" />
</f:facet>
<p:column headerText="Update" style="width:6%">
<p:rowEditor />
</p:column>
</p:dataTable>
<p:dialog id="modalDialog"
header="Delete User?"
modal="true"
resizable="false"
draggable="false"
widgetVar="delUserConf"
>
<h:panelGrid id="display" columns="2" style="width: 150px;">
<h:outputLabel value="Firat Name" style="font-weight: bold"/>
<h:outputText value="Last Name" style="border: none"/>
</h:panelGrid>
</p:dialog>
Here is the code in my bean for the edit functionality:
public String onEdit(RowEditEvent event)
{
User user=(User)event.getObject());
user.getFirstName();
}
I did not add the link that I have in my form which pops up the dialog.Also I read that this might be because of Lazy loading and I am not sure about it.I am populating my table with a list and not the model.
Could you let me know what should I do to make it work?
maybe you should switch to SessionBean scope because the scope view is released when there are changes in the view. Try SessionBean. Also you can call from view scope any sessionbean like this, where controladorMB is a sessionbean
public void detallesPersona() {
try {
FacesContext ctx = FacesContext.getCurrentInstance();
ValueExpression vex = ctx.getApplication().getExpressionFactory().createValueExpression(ctx.getELContext(), "#{controladorMB}", ControladorMB.class);
ControladorMB gMB = (ControladorMB) vex.getValue(ctx.getELContext());
this.setSelectedPersona(gMB.getPersonaBean().detallesPersonas(this.selectedPersona.getIdPersona()));
} catch (Exception e) {
JsfUtil.addErrorMessage(e, "Error: " + e.getMessage());
}
}
I am trying to use the feature of prime faces which allows user to edit the row data in the table itself.I have followed this link to achieve it:
http://www.primefaces.org/showcase/ui/datatableRowEditing.jsf
When I say edit user the new values which are entered are not sent to the bean.It still shows the old values only.
My code in JSF:
<p:dataTable value="#{mybean.userList}"
var="item"
id="dataTab"
widgetVar="usersTable"
tableStyleClass="data" paginator="true" rows="5"
filteredValue="#{userController.filteredUsers}"
editable="true"
rowKey="#{item}">
<p:ajax event="rowEdit" listener="#{mybean.onEdit}" update=":userForm:growl" />
<p:ajax event="rowEditCancel" listener="#{mybean.onCancel}" update=":userForm:growl" />
<f:facet name="header">
<p:outputPanel>
<h:outputText value="Search all fields:" />
<p:inputText id="globalFilter" onkeyup="('usersTable').filter()" style="width:150px" />
</p:outputPanel>
</f:facet>
<p:column sortBy="#{item.firstName}" filterBy="#{item.firstName}"
filterMatchMode="startsWith">
<p:cellEditor>
<f:facet name="header">
<h:outputText value="First Name" />
</f:facet>
<f:facet name="output">
<h:outputText value="#{item.firstName}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item.firstName}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column sortBy="#{item.lastName}" filterBy="#{item.lastName}" filterMatchMode="startsWith">
<p:cellEditor>
<f:facet name="header">
<h:outputText value="Last Name" />
</f:facet>
<p:column headerText="Update" style="width:6%">
<p:rowEditor />
</p:column>
</p:dataTable>
My code in bean:
public String onEdit(RowEditEvent event) {
User user=(User)event.getObject());
user.getFirstName();
}
code in the bean for getting the list in ui:
public List<UserBean> getUsersList(){
List<UserBean> retval = new ArrayList<>();
for (Object[] tuple : myFacade.getUserList()) {
UserBean ub = new UserBean();
ub.setFirstName((String) tuple[0]);
ub.setLastName((String)tuple[1]);
ub.setEmailAddress((String)tuple[2]);
ub.setOfficeNumber((String)tuple[3]);
ub.setRole((String)tuple[4]);
retval.add(ub);
}
return retval;
}
I have tried the suggestions that were given in some of the posts but they did not work.Could anyone let me know how can I get the new values.I am using glassfish 4.0,primefaces 3.5.
I was able to figure out the problem..Every time when I am getting the list in the getter method I am calling the database to load the data..But this should be done only if the list is null.The following code gives you a clear picture:
public List<UserBean> getUsersList(){
if(retval == null)
{
retval = new ArrayList<>();
for (Object[] tuple : myFacade.getUserList()) {
UserBean ub = new UserBean();
ub.setFirstName((String) tuple[0]);
ub.setLastName((String)tuple[1]);
ub.setEmailAddress((String)tuple[2]);
ub.setOfficeNumber((String)tuple[3]);
ub.setRole((String)tuple[4]);
retval.add(ub);
}
}
return retval;
}
So getUsersList is my value of var in the p:datatable and now when I call the onEdit it will check for the list if it is null it does a database call or does not call the database.
I try to devise flexible table containing dynamic columns for CRUD operations.
I use p:columns component to make dynamic columns, but those columns do not change value when I try to update it.
<h:form id="form">
<p:dataTable id="dataTable"
var="item"
value="#{tableEditorController.items}"
editable="true"
paginator="true"
rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,15">
<p:ajax event="rowEdit" listener="#{tableEditorController.onEdit}" />
<f:facet name="header">
#{tableEditorController.tableName}
</f:facet>
<p:columns value="#{tableEditorController.columns}"
var="column"
columnIndexVar="colIndex">
<f:facet name="header">#{column.header}</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{item[column.property]}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item[column.property]}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:columns>
<p:column>
<f:facet name="header">test</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{item['activityName']}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item['activityName']}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Edit" style="width:6%">
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
When I click on link in "Edit" column all the cells in selected row turn into text input fields.
If I edit a value in the "test" column and save, it saves properly as I expect.
But if I edit value using an input field in column which was generated by p:columns tag and try to save, it does not save changes.
I monitored http requests by Chrome Tools. The requests contain changed value in every case.
I ran my code under debugger and a RowEditEvent contains new data in first case and unchanged data object in second.
I cannot realize my mistake and only thing left I doubt is square braces notation.
I checked square braces notation using in "test" column and it works fine.
I use JSF 2.1.3 and Primefaces 3.3
Controller class is following:
#ManagedBean
#RequestScoped
public class TableEditorController {
private static List activityList;
static{
activityList = new ArrayList();
ActivityType at = new ActivityTypeImpl();
at.setActivityId(1L);
at.setActivityName("FirstActivity");
activityList.add(at);
at = new ActivityTypeImpl();
at.setActivityId(2L);
at.setActivityName("Second Activity");
activityList.add(at);
}
public void onEdit(RowEditEvent event){
FacesMessage msg = new FacesMessage("Row Edited");
msg.setDetail(event.toString() + event.getObject());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public void delete(Object id){
}
public List getItems(){
return activityList;
}
public String getTableName(){
return "Name of the Table";
}
public List<ColumnModel> getColumns(){
ColumnModel m1 = new ColumnModel("ID", "activityId");
ColumnModel m2 = new ColumnModel("Activity", "activityName");
return Arrays.asList(m1, m2);
}
}
I will appreciate any suggestion and/or idea.
I have found a way around p:columns. I replaced it with following code.
<c:forEach items="#{tableEditorController.columns}" var="column">
<p:column>
<f:facet name="header">#{column.header}</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{item[column.property]}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item[column.property]}" style="width:100%" disabled="#{not column.editable}"/>
</f:facet>
</p:cellEditor>
</p:column>
</c:forEach>
It works but I had to add JSTL library to project dependencies.