I'm working with JSF technology. I've 2 views and 2 beans. The first View (homepage.xhtml) sets a text parameter in the first Bean (UserBean) which is like so:
#ManagedBean
#SessionScoped
public class UserBean implements Serializable{
private String searchText;
public UserBean(){}
public String search() {
return "searching?faces-redirect=true&text="+searchText;
}
A commandButton in the view submits the search, and calls the UserBean.search().
I have this view in the searching.xhtml, which is a simple DataList component of PrimeFaces showing a list of a user:
<f:metadata>
<f:viewParam name="text" value="#{searchView.searchText}"/>
<f:event type="preRenderView" listener="#{searchView.init()}"></f:event>
</f:metadata>
<h:head>
<title>Search Results</title>
</h:head>
<h:body>
<h:form id="resultsForm">
<p:dataList var="user" value="#{searchView.results}" type="unordered" itemType="none" paginator="true" rows="10" styleClass="paginated">
<f:facet name="header">
Results for #{searchView.searchText}:
</f:facet>
<p:panel>
<p:commandLink update=":resultsForm:userDetail" oncomplete="PF('userDialog').show()" title="user dettagli" styleClass="ui-icon ui-icon-search" style="float:right;margin-right:50px">
<f:setPropertyActionListener value = "#{user}" target="#{searchView.selectedUser}"/>
<h:outputText value="#{user.firstName}, #{user.lastName}" />
</p:commandLink>
<h:outputText value="#{user.firstName} #{user.lastName} (#{user.email})" style="display:inline-block" />
</p:panel>
</p:dataList>
<p:dialog header="User Info" widgetVar="userDialog" modal="true" showEffect="blind" hideEffect="explode" resizable="false">
<p:outputPanel id="userDetail" style="text-align:center;">
<p:panelGrid columns="2" rendered="#{not empty searchView.selectedUser}" columnClasses="label,value">
<h:outputText value="First name:" />
<h:outputText value="#{searchView.selectedUser.firstName}" />
<h:outputText value="Last Name" />
<h:outputText value="#{searchView.selectedUser.lastName}" />
<h:outputText value="Calendar" />
<h:outputText value="#{searchView.selectedUser.visibility}" />
</p:panelGrid>
</p:outputPanel>
</p:dialog>
</h:form>
<br/>
</h:body>
In the end, I've this backing bean:
#ManagedBean
#ViewScoped
public class SearchView implements Serializable {
private List<User> results;
private User selectedUser;
private String searchText;
#EJB
private SearchingManager sm;
public void init() {
System.out.println("print search text:" + searchText);
results = sm.search(searchText);
}
public SearchView() {
}
public void setSelectedUser(User selectedUser) {
System.out.println("setter of selected user");
this.selectedUser = selectedUser;
}
public User getSelectedUser() {
System.out.println("getter of selected user");
return selectedUser;
}
It works and shows the results of the search correctly but when it opens the page of results I notice this output:
Informazioni: print search text: Mario
Informazioni: getter of selected user
So I'm wondering why that getSelectedUser() is called without selecting any user. Moreover when I select a user it shows an empty dialog and this is the outcome:
Informazioni: getter of selected user
Informazioni: getter of selected user
Informazioni: getter of selected user
Informazioni: print search text: Mario
Informazioni: getter of selected user
So it recalls the init() function why?
And the worst thing is that if we close the Dialog and reopen it, the result is something like that but with
Informazioni: print search text: null
and it stops because of NullPointerException.
I'm spending days searching about this setPropertyActionListener but I can't understand this behavior of the system.
Related
InputText field in the following dialog retains previous value even though I set it to blank before calling show(). The inputText field is only displayed blank when show() is called for the first time. My bean is session scoped.
<p:dialog id="dlgId" widgetVar="dlgVar" dynamic="true">
<h:form>
<h:panelGrid columns="1">
<h:outputLabel for="nametext" value="Name" />
<p:inputText id="nametext" value="#{myBean.name}" />
</h:panelGrid>
<p:commandButton value="Save" actionListener="#{myBean.saveAction}" />
</h:form>
public void add(TreeNode selectedTreeNode) {
setName("");
RequestContext.getCurrentInstance().execute("PF('dlgVar').show()");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
How can I get the inputTEext field to display the value I set before calling show() rather then the value previously entered by the user?
The thing is: you need to update your form. To make it, you can use one of these solutions.
Solution 1 : update it from your xhtml
<h:form id="form">
<h:panelGrid columns="1">
<h:outputLabel for="nametext" value="Name" />
<p:inputText id="nametext" value="#{myBean.name}" />
</h:panelGrid>
<p:commandButton value="Save" actionListener="#{myBean.saveAction}" update=":form" />
</h:form>
Solution 2 : update it from your managedBean
YourXhtml
<h:form id="form">
...
</h:form>
YourManagedBean
public void saveAction() {
...
name = "";
RequestContext.getCurrentInstance().update(":form");
}
You can also read this post Can I update a JSF component from a JSF backing bean method?.
Solution 3 : update it using an Ajax event
You can also add an ajax event
<p:commandButton value="Save" type="button" >
<p:ajax event="click" listener="#{myBean.saveAction}" update=":form"/>
</p:commandButton>
I have a p:inputTextarea and I need the value of it while processing the form. It turned out that every time I submit the form I get all the values except the one from the textarea. #{xyzUI.description} is a String object with regular getters and setters.
<ui:composition>
<h:form id="form1">
<p:panel rendered="...">
<p:panel id="formPanel">
<p:panelGrid columns="2" cellpadding="5">
<!-- other form elements -->
<p:outputLabel>Description:</p:outputLabel>
<p:inputTextarea value="#{xyzUI.description}" style="width: 350px;" counter="display" counterTemplate="{0} characters remaining" maxlength="2000" autoResize="true" rows="4" />
<h:panelGroup />
<h:outputText id="display" />
</p:panelGrid>
<p:commandButton rendered="#{not xyzUI.noChange}" action="#{xyzUI.submitForm}" update="formPanel" ajax="true" value="Apply" >
<p:ajax update="formPanel"></p:ajax>
</p:commandButton>
</p:panel>
</p:panel>
</h:form>
<ui:composition>
In my backing bean the value is always "". I don't know what's wrong.
public void submitForm()
{
...
tmp.setDescription(description); // String is always "" while debugging
myList.add(tmp);
RequestContext.getCurrentInstance().update("content");
}
I ran your code locally and discovered the issue. In the command button, remove the p:ajax call.
PrimeFaces command buttons are ajax enabled by default.
So change this:
<p:commandButton rendered="#{not xyzUI.noChange}" action="#{xyzUI.submitForm}" update="formPanel" ajax="true" value="Apply" >
<p:ajax update="formPanel"></p:ajax>
</p:commandButton>
To this:
<p:commandButton rendered="#{not xyzUI.noChange}" action="#{xyzUI.submitForm}" update="formPanel" value="Apply" />
My backing bean for reference
#ManagedBean
#ViewScoped
public class xyzUI implements Serializable{
private static final long serialVersionUID = 6259024062406526022L;
private String description;
private boolean noChange = false;
public xyzUI(){
}
public void submitForm(){
System.out.println(description);
}
public boolean isNoChange() {
return noChange;
}
public void setNoChange(boolean noChange) {
this.noChange = noChange;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Sidenote: It works with Command-Buttons.
What I Have:
A simple form where name and address from a customer are entered. In a data-table below, each row contained (in the working version) the following fields:
Name of the customer
A Command-Button which redirects to another page and shows the customers orders (This worked using <p: commandButton immediate="true">)
Another Command-Button which displayed the past orders.
Another Command-Button which was responsible for updating customer-data.
Since I didn't want to have three Command-Buttons in each row I decided to use a Split-Button.
Problem:
<p:splitButton immediate="true">
The form asks me to fill the missing data (name and address) which are set to required="true.
Question:
As far as I understand the attribute immediate="true is used to overcome this issue. So what am I missing ?
Code:
<h:form>
<p:growl id="growl" sticky="false" life="3500" showDetail="false"/>
<h:panelGrid id="customer_grid" columns="2" cellspacing="1" cellpadding="5">
<h:outputLabel id="label" for="name" value="Kunde:" style="font-weight:bold"/>
<p:inputText id="name" value="#{customerController.customer.name}" required="true" requiredMessage="Name eingeben!"/>
<h:outputLabel for="address" value="Adresse:" style="font-weight: bold" />
<p:inputText id="address" value ="#{customerController.customer.address}" required="true" requiredMessage="Adresse eingeben!"/>
<p:commandButton action = "#{customerController.createCustomer}" value="Speichern" style="margin-right:10px"
actionListener="#{growlController.saveMessage}" ajax="true"
onclick="PF('blockUIWidget').block()" oncomplete="PF('blockUIWidget').unblock()" styleClass="save-button"/>
<p:commandButton onclick="history.back(); return false;" value="Abbrechen" ajax="true"/>
<pe:blockUI widgetVar="blockUIWidget">
<h:panelGrid columns="2">
<p:graphicImage id="loader" name="images/ajax-loader.gif" style="margin-right: 12px; vertical-align: middle;" rendered="true"/>
<h:outputText value="Please wait..." style="white-space: nowrap;"/>
</h:panelGrid>
</pe:blockUI>
</h:panelGrid>
<br/>
<br/>
<p:dataTable var="customer" value="#{customerController.allCustomers}" resizableColumns="true" tableStyle="width: auto"
rendered="#{not empty customerController.allCustomers}">
<p:column headerText="customer" style="width: 300px">
<h:outputText value="#{customer.name}" />
</p:column>
<p:column>
<p:splitButton value="current order" action="#{userController.setup(customer, 'lastOrder')}" immediate="true">
<p:menuitem value="old orders" action="#{userController.setup(customer, 'oldOrders')}" immediate="true"/>
<p:menuitem value="edit" action="#{userController.setup(customer, 'update')}" immediate="true"/>
</p:splitButton>
</p:column>
</p:dataTable>
EDIT:
According to the comment of BalusC I've put the two parts in separate forms.
Effect: The message to fill out the above form does not show up, but the redirect is not happening either.
EDIT2:
The purpose of the method userController.setup(customer, 'String') is basically to inject the customer who is represented for each row. The String is returned for redirecting purposes which are set in the faces-config.xml and as I said: It works when I use Command-Buttons instead.
CODE:
#Named
#SessionScoped
public class UserController implements Serializable{
#Inject
private Customer customer;
#EJB
private CustomerService customerService;
public UserController(){
}
public List<Item> getItems(){
return customerService.getItems(customer);
}
public Ordery getCurrentOrder(){
return customerService.getCurrentOrder(customer);
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public CustomerService getCustomerService() {
return customerService;
}
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
public String setup(Customer customer, String nav){
this.customer = customer;
return nav;
}
public void update(){
customerService.update(customer);
}
}
I have a problem debugged for all half day. I still could not figure it out. Basically, I use datatable expandable feature to show some extra options for each row. User could check some or none of them, then user click on update button to update database. So one row will have many options.
<f:selectItems value="#{adminBean.allTabNames}" /> is to use collect users' selected options, then managed bean will save them into database once user clicks update.
Then problem is that public void setSelectedTabsNames(List<String> selectedTabsNames) {
this.selectedTabsNames = selectedTabsNames;
} method is called several times with expected values or null values(empty list). The values are passed randomly, sometimes there are no values.
View:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:form id="form1">
<p:growl id="growl" showDetail="true"/>
<p:dataTable var="user" value="#{adminBean.users}" scrollable="false"
>
<p:ajax event="rowToggle" listener="#{adminBean.onRowToggle(user.id)}" update=":form:tabView:form1:growl" />
<f:facet name="header">
All Users
</f:facet>
<p:column style="width:2%">
<p:rowToggler />
</p:column>
<p:column headerText="First Name">
<h:outputText value="#{user.firstname}" />
</p:column>
<p:column headerText="Last Name">
<h:outputText value="#{user.lastname}" />
</p:column>
<p:column headerText="Password">
<h:outputText value="#{user.password}" />
</p:column>
<p:column headerText="Active">
<h:outputText value="#{user.active}" />
</p:column>
<p:column headerText="Last Login">
<h:outputText value="#{user.timestamp}" />
</p:column>
<p:column headerText="Notes">
<h:outputText value="#{user.notes}" />
</p:column>
<p:rowExpansion>
<h:panelGrid id="display" columns="1" cellpadding="4">
<h:outputText value="Tabs: " />
<p:selectManyCheckbox id="grid" value="#{adminBean.selectedTabsNames}"
layout="pageDirection" >
**<f:selectItems value="#{adminBean.allTabNames}" />**
</p:selectManyCheckbox>
</h:panelGrid>
<br/>
<p:commandButton value="Update" id="submit" actionListener="#{adminBean.updateTabsForUser(user.id)}" ajax="true" />
</p:rowExpansion>
</p:dataTable>
</h:form>
Managed Bean:
setSelectedTabsNames(List selectedTabsNames)
package org.userlogin.view;
import java.io.Serializable;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ViewScoped;
import org.userlogin.db.entity.FopsUser;
import org.userlogin.service.UserService;
#ManagedBean
#ViewScoped
public class AdminBean implements Serializable {
private static final long serialVersionUID = -9002632063713324598L;
private List<FopsUser> users;
private List<String> selectedTabsNames;
private List<String> allTabNames;
private UserService us;
public AdminBean() {
us = new UserService();
users = us.getAllUsers();
allTabNames = us.getAllTabs();
}
public List<FopsUser> getUsers() {
return users;
}
public void setUsers(List<FopsUser> users) {
this.users = users;
}
public void setSelectedTabsNames(List<String> selectedTabsNames) {
this.selectedTabsNames = selectedTabsNames;
}
public List<String> getSelectedTabsNames() {
return selectedTabsNames;
}
public List<String> getAllTabNames() {
return allTabNames;
}
public void setAllTabNames(List<String> allTabNames) {
this.allTabNames = allTabNames;
}
public void updateTabsForUser(Long uid) {
us.updateTabsUser(selectedTabsNames);
}
public void onRowToggle(Long uid) {
//set current selected user
us.setCurrent(uid);
this.selectedTabsNames = us.getTabNamesByUserId(uid);
}
}
---------------update-------
Remove the nested 'form', but still not working. I found the the issue is not affecting the last row of data table. Suppose I have three rows in data table, the setters are called multiple times and set to null at last time when I manipulate the first two rows. But for the last row, the setter is still called multiple times. The last call sets the expected value. Now I just add
public void setSelectedOptions(List<String> selectedOptions) {
if (selectedOptions == null || selectedOptions.size() == 0) {
return;
}
this.selectedOptions = selectedOptions;
}
It is still ugly ...
------------update----------
<p:selectManyCheckbox id="grid" value="#{user.selectedTabsNames}"
layout="pageDirection" >
**<f:selectItems value="#{adminBean.allTabNames}" />**
</p:selectManyCheckbox>
Should design like this: put selectedTabsNames into User object. But still not working. since I have this ajax submit button, this requests each selectedTabsNames got called with empty list passed in.
<p:rowExpansion>
<h:panelGrid id="display" columns="1" cellpadding="4">
<h:outputText value="Tabs: " />
<p:selectManyCheckbox id="grid" value="# {user.selectedTabsNames}"
layout="pageDirection" >
<f:selectItems value="#{adminBean.allTabNames}" />
</p:selectManyCheckbox>
<p:commandButton value="Update" id="submit" ajax="true" />
</h:panelGrid>
<br/>
</p:rowExpansion>
----------------update with my own solution (not graceful one, but works) -----
Every time an ajax buttom has been clicked, the whole data table is updated. That means each setSelectedItem method will be called with expected value or empty value. I don't know how to change that.
So I modify my save() method called from ajax button with following logic:
public void save(Long userId, List<String> selectedItem) {
for (User user: users) {
if (user.getId() == userId) {
//update selectedItem in db for this user.
} else {
// read selectedItems in db
// update selectedItem in user object.
}
}
}
When the ajax event is fired, all the input elements in the form are sent. That means that all the selectManyCheckbox (one for each row) are sent. That's why setSelectedTabsNames is called several times.
You have to change how you have designed your implementation. One way woud be to store the selected options in the FopsUser object, so you could do value="#{user.selectedTabsNames}":
<p:selectManyCheckbox id="grid" value="#{user.selectedTabsNames}"
layout="pageDirection" >
**<f:selectItems value="#{adminBean.allTabNames}" />**
</p:selectManyCheckbox>
This way the selected tabs for each row are stored separately.
I may be wrong, but I don't think rowToggle event is the kind of ajax event that can handle row-level parameters. Think about it this way: var="user" is a row-iteration level variable, available for each row in the datatable. The rowToggle event on the other hand is a single level tag, applicable to the entire table as one component. So there probably isn't a reliable way for the datatable to know which row you're referring to when you use
adminBean.onRowToggle(user.id), it'll just select the last row that was rendered
A more effective way to get hold of the details of the row that was toggled is using the ToggleEvent listener in the backing bean, where you don't have to pass a variable:
public void onRowToggle(ToggleEvent te){
User theSelectedUser = (User)te.getData();
int id = theSelectedUser.getId();
}
In your view, you'll now have:
<p:ajax event="rowToggle" listener="#{adminBean.onRowToggle}" update=":form:tabView:form1:growl"/>
Im trying to implement the modification of an entity in JSF using Primefaces.
My main view, which lists the users is the following:
<p:growl id="growlEditUnit" showDetail="true" life="12000" />
<p:dialog id="dialogEditUnit" header="Edit Unit" widgetVar="editUnitDialog" showEffect="fade" hideEffect="fade" resizable="false" >
<ui:include src="editUnit.xhtml" />
</p:dialog>
<h:form id="form2">
<p:dataTable id="units" var="unit" value="#{unitController.unitsOfLoggedInUser}" >
<f:facet name="header">
Click Edit or Delete after selecting a unit to modify or remove it
</f:facet>
<p:column headerText="Code">
#{unit.unitCode}
</p:column>
<p:column headerText="Name">
#{unit.unitName}
</p:column>
<p:column headerText="Semester" >
#{unit.semester}
</p:column>
<p:column headerText="Academic Year">
#{unit.academicYear}
</p:column>
<p:column headerText="Twitter Username">
#{unit.twitterUsername}
</p:column>
<p:column headerText="Actions">
<p:commandButton id="editButton" value="Edit" action="#{unitController.setCurrent(unit)}" update=":dialogEditUnit" oncomplete"editUnitDialog.show()" />
</p:column>
</p:dataTable>
</h:form>
This view lists all the data correctly. However, when I press the current, my aim is to set the current attribute of the managed bean (code listed below) with the unit based on the button clicked. After this I try to update the edit dialog, so it will be filled with the values of that unit, and then make it visible using the oncomplete attribute. However, it seems that the managed been method setCurrent(unit) is never called when clicking the edit button. Subsequently the dialog is shown empty. Can someone help me with what am I doing wrong?
I am posting the managed bean code too.
#ManagedBean(name = "unitController")
#ViewScoped
public class UnitController implements Serializable {
private Unit current;
private List<Unit> unitsOfLoggedInUser;
#ManagedProperty(value="#{loginController.checkedUser}")
private Lecturer lecturer;
#EJB
private web.effectinet.ejb.UnitFacade ejbFacade;
#EJB
private web.effectinet.ejb.LecturerFacade lecturerFacade;
public UnitController() {
}
#PostConstruct
public void init(){
if (lecturer.getLecturerId() == null)
unitsOfLoggedInUser = null;
else
unitsOfLoggedInUser = (List<Unit>) lecturer.getUnitCollection();
}
public List<Unit> getUnitsOfLoggedInUser() {
return unitsOfLoggedInUser;
}
public void setCurrent(Unit current) {
this.current = current;
}
public Lecturer getLecturer() {
return lecturer;
}
public void setLecturer(Lecturer lecturer) {
this.lecturer = lecturer;
}
The action attribute of the commandButton is rendered without information on the value of the unit variable.
To pass the unit to the action method of your managed bean, then you need to pass the ID of unit in an <f:param> child tag of commandButton.
<p:commandButton action="#{managedBean.actionMethod}" ........>
<f:param name="unitid" value="#{unit.id}" />
</p:commandButton>
From your action method you can get the request parameter by the name from the ExternalContext and this will give you the ID of the unit that the commandButton was pressed for in your dataTable.