I currently have a primefaces datatable table with a conditional delete button that will delete the row if clicked. Clicking on it the first time works. It would delete the row and the table will be refreshed with the new table. When I try to delete something from the table again, the table would refresh itself with no entries. If I update the table using one of the buttons that I created, the table would show up again with the entry that I tried to delete still there. Looking into it, I see that the method in action is being called when I deleted the first one successfully. However, when I try it again, the method is not being invoked. Why isn't it?
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
</h:head>
<h:body>
<h:form>
<p:dataTable id="carTable" var="car" value="#{dtBasicView.cars}">
<f:facet name="header">
Car Table
</f:facet>
<p:column headerText="Id" sortBy="#{car.id}">
<h:outputText value="#{car.id}" />
</p:column>
<p:column headerText="Year" sortBy="#{car.year}">
<h:outputText value="#{car.year}" />
</p:column>
<p:column headerText="Brand" sortBy="#{car.brand}">
<h:outputText value="#{car.brand}" />
</p:column>
<p:column headerText="Color" sortBy="#{car.color}">
<h:outputText value="#{car.color}" />
</p:column>
<p:column headerText="Delete Option">
<p:commandLink action="#{dtBasicView.deleteCar(car)}"
update="#form" rendered="#{car.isWhite}" value="Delete" ajax="true">
</p:commandLink>
</p:column>
</h:form>
</h:body>
</html>
And the bean
#ManagedBean(name="dtBasicView")
#ViewScoped
public class BasicView implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Car selectedCar;
private List<Car> cars;
private List<Car> oneHundredCars;
private int numberOfcars=0;
#ManagedProperty("#{carService}")
private CarService service;
#PostConstruct
public void init() {
oneHundredCars = service.createCars(100);
}
public void setNumberOfcars(String num) {
this.numberOfcars = Integer.parseInt(num);
cars = oneHundredCars.subList(0, numberOfcars);
}
public List<Car> getCars() {
return cars;
}
public void setService(CarService service) {
this.service = service;
}
public Car getSelectedCar() {
return selectedCar;
}
public void setSelectedCar(Car selectedCar) {
this.selectedCar = selectedCar;
}
public boolean getIsEmpty() {
return cars == null || cars.isEmpty();
}
public void deleteCar(Car car) {
cars.remove(car);
int size = cars.size();
setNumberOfcars(""+size);
}
}
A little update: I still haven't fixed my problem. I have shifted some things around so that the list is not resizeable. Now whenever I click on the second delete commandlink, the whole datatable gets refreshed with new random data.
Another update: It appears as if it is calling the #PostConstruct again after hitting the second delete. By doing so, it is recreating a whole new set of arrays of cars.
After spending the whole day yesterday trying to figure out why this is happening, I have finally fixed it. I have changed the commandlink to commandbutton and neither of those changes worked. What worked for me was instead of letting the button be an ajax submit, it would instead be a non-ajax submit. I still do not know why this worked, so if anyone can explain it would be greatly helpful.
Related
The goal is to automatically select the first row of the datatable when the user filters it.
PostFilter event is implemented in order to select the first row but it happens it is actually overriden by whatever event happening afterwards and setting the initial selected row back.
<h:form id="customerForm">
<p:commandButton value="selection change" action="#{customerControllerv1.selectionChange}"/>
<p:commandButton value="selection show" action="#{customerControllerv1.selectionShow}"/>
<p:dataTable id="dtCustomer" var="customer" value="#{customerControllerv1.customers}" rowKey="#{customer.id}"
selection="#{customerControllerv1.selectedCustomer}" selectionMode="single"
binding="#{customerControllerv1.uiCustomers}">
<f:event type="org.primefaces.event.data.PostFilterEvent" listener="#{customerControllerv1.postFilter()}" />
<p:column headerText="Id">
<h:outputText value="#{customer.id}" />
</p:column>
<p:column headerText="First Name" filterBy="#{customer.firstName}" filterMatchMode="contains" >
<h:outputText value="#{customer.firstName}" />
</p:column>
<p:column headerText="Last Name" filterBy="#{customer.lastName}" filterMatchMode="contains">
<h:outputText value="#{customer.lastName}" />
</p:column>
</p:dataTable>
</h:form>
#ManagedBean(name = "customerControllerv1")
#ViewScoped
public class CustomerControllerv1 implements Serializable {
private static final long serialVersionUID = 1L;
private Customer selectedCustomer;
private DataTable uiCustomers;
private List<Customer> customers = new ArrayList<Customer>();
public CustomerControllerv1() {
}
#PostConstruct
void init() {
CustomerDAO custDAO = new CustomerDAO();
customers = custDAO.getAllCustomers();
// select first row
if (customers.size()>0) selectedCustomer=customers.get(0);
}
public void postFilter () {
selectionChange();
}
public void selectionChange () {
RequestContext context = RequestContext.getCurrentInstance();
List<Customer> sortedList = (List<Customer>)uiCustomers.getValue();
// select first row of the filtered list and render the DataTable
if (sortedList.size()>0) selectedCustomer=sortedList.get(0);
context.update("customerForm:dtCustomer");
}
public void selectionShow () {
System.out.println( "selectionShow: "+selectedCustomer.getId() );
}
// getters and setters
....
}
selectionChange method is called by postFilter as well as from the button in the xhtml page. Clicking the selection change button selects the first row as expected. Clicking the selectionShow button will prove it.
Entering data in the filter of the xhtml page also calls the same code but the first row selection is overidden afterwards. Clicking the selectionShow button will demonstrate it.
Does anybody have any idea about how to solve this?
I thought I'd try and get a primefaces datagrid working with my JSF code, but I always got "no results found". So I'm trying to set up a simple example but I get the same error messages so I must be doing something fundamentally wrong.
I have the following backing bean:
#ManagedBean
#ViewScoped
public class CarBean {
private static final Logger logger = Logger.getLogger("datagrid.ejb.CarBean");
private List<Car> cars;
public CarBean() {
cars = new ArrayList<Car>();
cars.add(new Car("myModel",2005,"ManufacturerX","blue"));
logger.log(LogLevel.INFO, "added car");
//add more cars
}
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
}
And the following xhtml page:
<!DOCTYPE html>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<p:dataGrid var="car" value="#{carBean.cars}" columns="3"
rows="12"layout="grid">
<p:column>
<p:panel header="#{car.model}">
<h:panelGrid columns="1">
<p:graphicImage value="/images/cars/#{car.manufacturer}.jpg"/>
<h:outputText value="#{car.year}" />
</h:panelGrid>
</p:panel>
</p:column>
</p:dataGrid>
</h:body>
</html>
I can see from the logs and debugger that the CarBean is instantiated but still I get the no records found error. Any ideas?
Thanks,
Zobbo
Sample.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<f:event listener="#{sample.dosamplelist}" type="preRenderView" />
</h:head>
<h:body>
<h:form>
<h:panelGrid id="samplesetting" columns="6" cellpadding="5">
<f:facet name="header">Name Setting</f:facet>
<h:outputLabel for="samplename" value="Name:" />
<p:inputText value="#{sample.name}" id="samplename"
required="true" label="samplename" />
</h:panelGrid>
<p:panel id="sampleview" header="Sample List">
<p:dataTable var="spl" value="#{sample.samplelist}" rowKey="#{spl.name}"
selection="#{sample.selectedname}"
selectionMode="single">
<p:column headerText="Name">
<h:outputText value="#{spl.name}" />
</p:column>
<p:column>
<p:commandButton id="one" value="View Details" action="#{sample.setSelectedsample(spl)}" update="#form:samplesetting">
</p:commandButton>
</p:column>
</p:dataTable>
</p:panel>
</h:form>
Managed Bean
#SuppressWarnings("serial")
#ManagedBean(name = "sample")
#RequestScoped
public class Sample implements Serializable
{
private String name;
private List<Sample> samplelist;
private String selectedname;
//getters and setters
public void dosamplelist(ComponentSystemEvent event)
{
List<Sample> samplelist = new ArrayList<Sample>();
Sample configA = new Sample();
configA.setName("John");
samplelist.add(configA);
Sample configB = new Sample();
configB.setName("David");
samplelist.add(configB);
this.samplelist = samplelist;
}
public void setSelectedsample(Sample smpl)
{
this.name = smpl.name;
}
}
This is the sample of little big form, and the need is, when we select the table row from the bottom, it will be display to top input box for editing purpose.
But when I press the command button it do not work. why? and what is the reason please?
Possible Problem
One obvious problem is that at the class level, you've defined:
private List<Sample> samplelist;
Then you go ahead and hide the variable in doSampleList with
List<Sample> samplelist = new ArrayList<Sample>();
Combined with the fact that you have your bean marked as #RequestScoped, it will guarantee that the content of the samplelist will not be consistent during the JSF request processing.
To Solve:
Mark your bean as #ViewScoped instead and resolve the variable hiding problem as you see fit.
Further reading:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
I'm using an editable Primefaces p:datatable to show the data to the user. In this datatable, I have a p:column with a h:selectOneMenu, and another one with a p:selectBooleanCheckbox.
I want to check or uncheck and disable or enable the checkbox depending on the value selected in the h:selectOneMenu.
If I only had one h:selectOneMenu and one p:selectBooleanCheckbox, I'd use a p:ajax to attach a listener to the change event, and I'd manipulate the p:selectBooleanCheckbox in this method. But I have a pair of h:selectOneMenu and p:selectBooleanCheckbox per row and I don't know how to do this.
This is what I tried:
<h:form>
<p:dataTable var="appointment" value="#{prescController.appointmentsToday}" editable="true" id="tblAppointments">
<p:ajax event="rowEdit"
listener="#{prescController.onEdit}" update=":messages" />
<p:column sortBy="presc.drug" headerText="Drug">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{appointment.presc.drug.name}" />
</f:facet>
<f:facet name="input">
<h:selectOneMenu value="#{appointment.presc.drug}"
converter="#{drugConverter}" required="true">
<f:selectItem itemLabel="" noSelectionOption="true" />
<f:selectItems value="#{prescController.drugs}"
var="drug" itemLabel="#{drug.name}" />
<p:ajax update="autoAmount" />
</h:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
<p:column sortBy="presc.autoAmount" headerText="Auto amount">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="Y"
rendered="#{not empty appointment.presc.drug.rules and appointment.presc.autoAmount}" />
<h:outputText value="N"
rendered="#{empty appointment.presc.drug.rules or not appointment.presc.autoAmount}" />
</f:facet>
<f:facet name="input">
<p:selectBooleanCheckbox id="autoAmount"
value="#{not empty appointment.presc.drug.rules and appointment.presc.autoAmount}"
disabled="#{appointment.presc.drug.name eq 'somethingsomething'}" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column>
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
The post Retrieving other component's client ID in JSF 2.0 describes how to retrieve ids of other components in a page. In my opinion, the #{p:component('sampleButton')} should find the next component having this ID in the component tree - this should be the same row.
Alternatively, you should be able to rerender the whole row via JSF 2 #{component.parent.clientId} functionality (measure out, how many "parent" steps you need, e.g. #{component.parent.parent.clientId}).
Hope it helps, else just add comments... :-)
I can't imagine why you are unsatisfied with simple update="checkboxId"but what you can try is updating component through widgetVar which you can generate during page render.
Tiny example:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Table Example</title>
</h:head>
<h:body>
<h:form prependId="false">
<p:dataTable var="data" value="#{tableBean.data}">
<p:column headerText="Command">
<p:commandButton value="Toggle" actionListener="#{tableBean.toggleSelection(data.id)}"
update="#widgetVar(tableCheckboxComponent_#{data.id})" />
</p:column>
<p:column headerText="Value">
<h:outputText value="#{data.value}" />
</p:column>
<p:column headerText="Selected">
<p:selectBooleanCheckbox widgetVar="tableCheckboxComponent_#{data.id}" value="#{data.selected}" />
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
Backing bean:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class TableBean {
private Map<String, MyData> data;
public List<MyData> getData(){
return new ArrayList<MyData>(data.values());
}
public TableBean() {
data = new HashMap<String, MyData>();
for (int i = 0; i<22; i++) {
String id = "id" + Integer.toString(i);
data.put(id, new MyData( id , i));
}
}
public void toggleSelection(String id) {
MyData myData = data.get(id);
myData.setSelected(!myData.isSelected());
}
}
And Data object:
public class MyData {
private String id;
private boolean selected;
private int value;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public MyData(String id, int value) {
this.id = id;
this.value = value;
this.selected = false;
}
}
I still don't know why my approach didn't work.
In the end, I added a listener to the p:ajax component to manipulate the SelectBooleanCheckbox in the managed bean
<p:ajax listener="#{prescBean.onDrugSelected}" update="autoAmount" />
public void onDrugSelected(AjaxBehaviorEvent event) {
Drug drug = (Drug) ((UIOutput) event
.getSource()).getValue();
boolean hasRules = drug.getRules().size() > 0;
SelectBooleanCheckbox cbAutoAmount = (SelectBooleanCheckbox) ComponentUtils
.findComponent(FacesContext.getCurrentInstance().getViewRoot(),
"autoAmount");
cbAutoAmount.setDisabled(!hasRules);
cbAutoAmount.setValue(hasRules);
}
I am following the example given here. I have to show CheckBox and RadioButton for a list of Employees, where user can select many CheckBoxs, but only one RadioButton. Just the normal behaviour. I started with Radiobutton first and after running all my radiobuttons are selected automatically.
I have the below index.xhtml page
<!DOCTYPE html>
<html lang="en"
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">
<f:event listener="#{userPreferenceBean.preRender}" type="preRenderView" />
<h:head>
<title>Datatable with Checkbox and RadioButton Example</title>
</h:head>
<h:body>
<h:form>
<p:dataTable id="employeeDataTable" var="employee" value="#{userPreferenceBean.employeeList}"
rowKey="#{userPreferenceBean.employeeDataModel}" paginator="true" rows="10"
selection="#{userPreferenceBean.selectedEmployeeList}">
<f:facet name="header">
Showing employee List
</f:facet>
<p:column selectionMode="single" style="width:2%"></p:column>
<p:column headerText="Name" style="width:48%">
#{employee.name}
</p:column>
<p:column headerText="Department" style="width:48%">
#{employee.department}
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
My Backing bean is:
#ManagedBean
#SessionScoped
public class UserPreferenceBean implements Serializable{
private static final long serialVersionUID = 1L;
private List<Employee> employeeList;
private List<Employee> selectedEmployeeList;
private EmployeeDataModel employeeDataModel;
public void preRender(ComponentSystemEvent ebent){
System.out.println("Inside prerender");
}
#PostConstruct
public void initializeEmployeeList(){
createEmployeeList();
employeeDataModel = new EmployeeDataModel(employeeList);
}
private void createEmployeeList(){
employeeList = new ArrayList<>();
employeeList.add(new Employee("Sudipta",29,"Computer"));
employeeList.add(new Employee("Bunty", 29, "Electrical"));
employeeList.add(new Employee("Pradipta", 24, "Computer"));
}
//Other Getter and Setters
Below is the POJO Class of Employee:
public class Employee implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String department;
//Constructor and Getters+Setters
And this is my DataModel class:
public class EmployeeDataModel extends ListDataModel<Employee> implements SelectableDataModel<Employee>{
public EmployeeDataModel(){
}
public EmployeeDataModel(List<Employee> employees){
super(employees);
}
#Override
public Employee getRowData(String rowKey) {
#SuppressWarnings("unchecked")
List<Employee> employees = (List<Employee>) getWrappedData();
for(Employee employee : employees){
if(employee.getName().equals(rowKey))
return employee;
}
return null;
}
#Override
public Object getRowKey(Employee employee) {
return employee.getName();
}
}
Do you have any idea why all radiobuttons are getting selected automatically and what changes I need to do? Thanks. Attached is the screenshot
You are not using the employeeDataModel properly, your value attribute of the table should be init in the following way
value="#{userPreferenceBean.employeeDataModel}"
and I think you can remove the rowKey attribute
Take a look at the following example DataTable - Instant Row Selection
I don't think it's possible to have a list of radiobuttons where only 1 can be selected and then 1 checkbox to select all the radiobuttons. Normal behavior with radiobuttons is that only 1 can be selected. If you only use checkboxes this is possible, but even then only the displaying page will be selected. You can test this in the showcase.
If I were you I would implement the solution with only the checkboxes.
Finally I am able to solve the problem. The problem was below:
Since my selectionMode was single like
<p:column selectionMode="single" style="width:2%"></p:column>
so I need selection="#{userPreferenceBean.selectedEmployee}" rather than the list of employees.
Now the index.xhtml looks like:
<p:dataTable id="employeeDataTable" var="employee" value="#{userPreferenceBean.employeeDataModel}"
paginator="true" rows="10" selection="#{userPreferenceBean.selectedEmployee}">
<f:facet name="header">
Showing employee List
</f:facet>
<p:column selectionMode="single" style="width:2%" />
<p:column headerText="Name" style="width:48%">
#{employee.name}
</p:column>
<p:column headerText="Department" style="width:48%">
#{employee.department}
</p:column>
</p:dataTable>
And I added the below member in my backing bean.
private Employee selectedEmployee; with getters and setters. Now it is working fine.
Full code is # myGitHubRepo
Thanks.