I am trying to implement row selection for a datatable with primefaces, but when I click on a row, nothing displays. I've narrowed it down to the setter for the selected car is not getting called, but I do not know how to set this. Here's my code, can anybody help?
TableBean
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean(name="TableBean")
#ViewScoped
public class ViewCDeployments implements Serializable {
private static final long serialVersionUID = 2213388781051004157L;
private final static String[] colors;
private final static String[] manufacturers;
static {
colors = new String[10];
colors[0] = "Black";
colors[1] = "White";
colors[2] = "Green";
colors[3] = "Red";
colors[4] = "Blue";
colors[5] = "Orange";
colors[6] = "Silver";
colors[7] = "Yellow";
colors[8] = "Brown";
colors[9] = "Maroon";
manufacturers = new String[10];
manufacturers[0] = "Mercedes";
manufacturers[1] = "BMW";
manufacturers[2] = "Volvo";
manufacturers[3] = "Audi";
manufacturers[4] = "Renault";
manufacturers[5] = "Opel";
manufacturers[6] = "Volkswagen";
manufacturers[7] = "Chrysler";
manufacturers[8] = "Ferrari";
manufacturers[9] = "Ford";
}
private List<Car> cars;
private Car selectedCar;
private Car[] selectedCars;
private CarDataModel mediumCarsModel;
public ViewCDeployments() {
cars = new ArrayList<Car>();
populateRandomCars(cars, 50);
mediumCarsModel = new CarDataModel(cars);
}
public Car[] getSelectedCars() {
return selectedCars;
}
public void setSelectedCars(Car[] selectedCars) {
this.selectedCars = selectedCars;
}
public Car getSelectedCar() {
return selectedCar;
}
public void setSelectedCar(Car selectedCar) {
this.selectedCar = selectedCar;
}
private void populateRandomCars(List<Car> list, int size) {
for(int i = 0 ; i < size ; i++)
list.add(new Car(getRandomModel(), getRandomYear(), getRandomManufacturer(), getRandomColor()));
}
private int getRandomYear() {
return (int) (Math.random() * 50 + 1960);
}
private String getRandomColor() {
return colors[(int) (Math.random() * 10)];
}
private String getRandomManufacturer() {
return manufacturers[(int) (Math.random() * 10)];
}
private String getRandomModel() {
return UUID.randomUUID().toString().substring(0, 8);
}
public CarDataModel getMediumCarsModel() {
return mediumCarsModel;
}
public List<Car> getCars() {
return cars;
}
}
Car.java
import java.io.Serializable;
public class Car implements Serializable {
/**
*
*/
private static final long serialVersionUID = 240545116337689611L;
private String model;
private int year;
private String manufacturer;
private String color;
private int price;
public Car(String model, int year, String manufacturer, String color) {
this.model = model;
this.year = year;
this.manufacturer = manufacturer;
this.color = color;
}
public Car(String model, int year, String manufacturer, String color, int price) {
this.model = model;
this.year = year;
this.manufacturer = manufacturer;
this.color = color;
this.price = price;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
#Override
public boolean equals(Object obj) {
if(obj == null)
return false;
if(!(obj instanceof Car))
return false;
Car compare = (Car) obj;
return compare.model.equals(this.model);
}
#Override
public int hashCode() {
int hash = 1;
return hash * 31 + model.hashCode();
}
#Override
public String toString() {
return "Car{" + "model=" + model + ", year=" + year + ", manufacturer=" + manufacturer + ", color=" + color + ", price=" + price + '}';
}
}
CarDataModel
import java.io.Serializable;
import java.util.List;
import javax.faces.model.ListDataModel;
import org.primefaces.model.SelectableDataModel;
public class CarDataModel extends ListDataModel<Car> implements SelectableDataModel<Car>, Serializable {
/**
*
*/
private static final long serialVersionUID = -5147159758418722534L;
public CarDataModel() {
}
public CarDataModel(List<Car> data) {
super(data);
}
#SuppressWarnings("unchecked")
#Override
public Car getRowData(String rowKey) {
//In a real app, a more efficient way like a query by rowKey should be implemented to deal with huge data
List<Car> cars = (List<Car>) getWrappedData();
for(Car car : cars) {
if(car.getModel().equals(rowKey))
return car;
}
return null;
}
#Override
public Object getRowKey(Car car) {
return car.getModel();
}
}
XHTML
<ui:composition 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"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:form id="form">
<p:dataTable id="cars" var="car" value="#{TableBean.mediumCarsModel}" paginator="true" rows="10"
selection="#{TableBean.selectedCar}">
<f:facet name="header">
RadioButton Based Selection
</f:facet>
<p:column selectionMode="single" style="width:18px" />
<p:column headerText="Model">
#{car.model}
</p:column>
<p:column headerText="Year">
#{car.year}
</p:column>
<p:column headerText="Manufacturer" >
#{car.manufacturer}
</p:column>
<p:column headerText="Color">
#{car.color}
</p:column>
<f:facet name="footer">
<p:commandButton id="viewCommand" value="View" icon="ui-icon-search"
update=":frmContent:form:displaySingle" oncomplete="singleCarDialog.show()"/>
</f:facet>
</p:dataTable>
<p:dialog id="dialog" header="Car Detail" widgetVar="singleCarDialog" resizable="false"
showEffect="fade" hideEffect="explode">
<h:panelGrid id="displaySingle" columns="2" cellpadding="4">
<f:facet name="header">
Header
</f:facet>
<h:outputText value="Model:" />
<h:outputText value="#{TableBean.selectedCar.model}" />
<h:outputText value="Year:" />
<h:outputText value="#{TableBean.selectedCar.year}" />
<h:outputText value="Manufacturer:" />
<h:outputText value="#{TableBean.selectedCar.manufacturer}" />
<h:outputText value="Color:" />
<h:outputText value="#{TableBean.selectedCar.color}" />
</h:panelGrid>
</p:dialog>
</h:form>
</ui:composition>
Just add to your datatable rowKey. Without this property selection won't work.
<p:dataTable id="cars" var="car" value="#{TableBean.mediumCarsModel}" paginator="true" rows="10" rowKey="#{car.manufacturer}" selection="#{TableBean.selectedCar}">
The rowKey must be the unique in the list of values.
I think you have added too much code.
See the example below :
test.xhml
<?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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
>
<h:head>
<title>PrimeFaces AJAX Enabled SelectOneMenu</title>
<style>
.ui-widget,.ui-widget .ui-widget {
font-size: 90% !important;
}
</style>
</h:head>
<h:body>
<h:body>
<h:form id="form">
<p:dataTable id="cars" var="car" value="#{testBean.cars}">
<p:column headerText="Model" style="width:24%">
<h:outputText value="#{car.model}" />
</p:column>
<p:column headerText="Year" style="width:24%">
<h:outputText value="#{car.year}" />
</p:column>
<p:column headerText="Manufacturer" style="width:24%">
<h:outputText value="#{car.manufacturer}" />
</p:column>
<p:column headerText="Color" style="width:24%">
<h:outputText value="#{car.color}" />
</p:column>
<p:column style="width:4%">
<p:commandButton id="selectButton" update=":form:display"
oncomplete="carDialog.show()" icon="ui-icon-search" title="View">
<f:setPropertyActionListener value="#{car}"
target="#{testBean.selectedCar}" />
</p:commandButton>
</p:column>
</p:dataTable>
<p:dialog header="Car Detail" widgetVar="carDialog" resizable="false"
id="carDlg" showEffect="fade" hideEffect="explode" modal="true">
<h:panelGrid id="display" columns="2" cellpadding="4"
style="margin:0 auto;">
<h:outputText value="Model:" />
<h:outputText value="#{testBean.selectedCar.manufacturer}"
style="font-weight:bold" />
</h:panelGrid>
</p:dialog>
</h:form>
</h:body>
</h:body>
</html>
BackBean
package com.jmxwebapp.mbeans;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean(name = "testBean")
#ViewScoped
public class CarBean {
private List<Car> cars;
private Car selectedCar;
public CarBean() {
cars = new ArrayList<Car>();
cars.add(new Car("Test", 2013, "Toyo", "Blue"));
cars.add(new Car("Test1", 2013, "Toyo", "Red"));
}
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
public Car getSelectedCar() {
return selectedCar;
}
public void setSelectedCar(Car selectedCar) {
this.selectedCar = selectedCar;
}
}
Car
package com.jmxwebapp.mbeans;
import java.io.Serializable;
public class Car implements Serializable {
/**
*
*/
private static final long serialVersionUID = 240545116337689611L;
private String model;
private int year;
private String manufacturer;
private String color;
private int price;
public Car(String model, int year, String manufacturer, String color) {
this.model = model;
this.year = year;
this.manufacturer = manufacturer;
this.color = color;
}
public Car(String model, int year, String manufacturer, String color, int price) {
this.model = model;
this.year = year;
this.manufacturer = manufacturer;
this.color = color;
this.price = price;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
#Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof Car))
return false;
Car compare = (Car) obj;
return compare.model.equals(this.model);
}
#Override
public int hashCode() {
int hash = 1;
return hash * 31 + model.hashCode();
}
#Override
public String toString() {
return "Car{" + "model=" + model + ", year=" + year + ", manufacturer=" + manufacturer + ", color=" + color + ", price=" + price + '}';
}
}
**Try above it should work**
The problem is with dialog component. In your dialog component You're using the same object where store selected car object (selectedCar). Pages are renderized from top to bottom. Therefore when You make clic the value stored is selectedCar object from dialog component. This value is initialized in null firstly.
For this You should be other object in your dialog component.
Notice that when you are using your beans you include them "inside" the html component, like:
<p:column headerText="Model">
#{car.model}
</p:column>
When you should be incluiding the bean inside the tag in the value option:
<p:column headerText="Model" value="#{car.model}>
</p:column>
Hope it works :)
Related
I have a drop down (p:selectOneMenu) as the input field in the Primefaces 8.0 datatable row, after I select the value in the drop down, if I sort it the selected value can be kept after ajax submit. However if I input a filter that filter 0 rows, and then I clear the filter, the selected value in the drop down disappear:
updated base on Kukeltje's request for adding input text:
Select the drop down value
input the filter so that all the rows are filter out
clear the filter, the selected value disappear
My backing bean:
package sample;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#Named
#SessionScoped
public class SampleBean implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 5307652891294044974L;
private static final Map<String, String> dropDown = new HashMap<>();
static {
dropDown.put("K1", "K1");
dropDown.put("K2", "K2");
dropDown.put("K3", "K3");
}
public Map<String, String> getDropDown() {
return dropDown;
}
private List<TableObject> tableObjects = Arrays.asList(new TableObject[] {new TableObject(), new TableObject()});
public List<TableObject> getTableObjects() {
return tableObjects;
}
public void setTableObjects(List<TableObject> tableObjects) {
this.tableObjects = tableObjects;
}
public static class TableObject
{
private String dd;
private String inputText;
public String getDd() {
return dd;
}
public void setDd(String dd) {
this.dd = dd;
}
public String getInputText() {
return inputText;
}
public void setInputText(String inputText) {
this.inputText = inputText;
}
}
}
My facelet:
<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" xmlns:o="http://omnifaces.org/ui"
xmlns:of="http://omnifaces.org/functions">
<h:head>
<title>Hello World JSF 2.3</title>
</h:head>
<h:body>
<h:form>
<p:dataTable var="item" value="#{sampleBean.tableObjects}"
widgetVar="itemTable">
<p:ajax event="sort" process="#this" update="#this"
skipChildren="false" />
<p:ajax event="page" process="#this" update="#this"
skipChildren="false" />
<p:ajax event="filter" process="#this" update="#this" global="false"
skipChildren="false" />
<p:column headerText="Dropdown" sortBy="#{item.dd}"
filterBy="#{item.dd}" filterMatchMode="contains">
<p:selectOneMenu id="Dropdown" value="#{item.dd}" required="false"
label="Dropdown" style="width: 90%">
<f:selectItem itemValue="#{null}" itemLabel="" />
<f:selectItems value="#{sampleBean.dropDown.entrySet()}"
var="entry" itemValue="#{entry.value}" itemLabel="#{entry.key}" />
</p:selectOneMenu>
</p:column>
<p:column id="InputTextHeader" headerText="Input Text"
sortBy="#{item.inputText}" filterBy="#{item.inputText}"
filterMatchMode="contains">
<p:inputText id="InputText" value="#{item.inputText}" />
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
I push my testing project to github, in case you want to test it
git clone https://github.com/saycchai/jsf-test.git
cd jsf-test
chmod +x *.sh
./buildAndRun.sh
for payara server:
browse: http://localhost:8080/index.xhtml
for other server:
http://localhost:8080/jsf-test/index.xhtml
Finally I found a work around solution as follows:
I added a phase listener, if the filter submit 0 row (pass as a request parameter, please see the onstart part in the facelet), then backup the Dd value to previousDd before the APPLY_REQUEST_VALUES phase and set the backup value previousDd back to Dd before the RENDER_RESPONSE phase, code as follows:
Backing Bean
package sample;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import javax.persistence.Transient;
#Named
#SessionScoped
public class SampleBean implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 5307652891294044974L;
private static final Map<String, String> dropDown = new HashMap<>();
static {
for(int i=1; i<10; i++) {
dropDown.put("K"+i, "K"+i);
}
}
public Map<String, String> getDropDown() {
return dropDown;
}
private List<TableObject> tableObjects = Arrays.asList(new TableObject[] {new TableObject(), new TableObject(), new TableObject(), new TableObject()});
public List<TableObject> getTableObjects() {
return tableObjects;
}
public void setTableObjects(List<TableObject> tableObjects) {
this.tableObjects = tableObjects;
}
public static class TableObject
{
private String dd;
private String inputText;
public String getDd() {
return dd;
}
public void setDd(String dd) {
this.dd = dd;
}
public String getInputText() {
return inputText;
}
public void setInputText(String inputText) {
this.inputText = inputText;
}
#Transient
private String previousDd;
public String getPreviousDd() {
return previousDd;
}
public void setPreviousDd(String previousDd) {
this.previousDd = previousDd;
}
}
}
Facelet
<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>
<title>Hello World JSF 2.3</title>
</h:head>
<h:body>
<h:form id="form">
<p:dataTable id="itemTable" var="item" value="#{sampleBean.tableObjects}"
widgetVar="itemTable"
paginator="true"
>
<p:ajax event="sort" process="#this" update="#this"
skipChildren="false" />
<p:ajax event="page" process="#this" update="#this"
skipChildren="false"
/>
<p:ajax event="filter" process="#this" update="#this" global="false"
skipChildren="false"
onstart="cfg.ext.params.push({name: 'tableFilterCount', value: PF('itemTable').paginator.cfg.rowCount});"
/>
<p:column id="DropdownHeader" headerText="Dropdown" sortBy="#{item.dd}"
filterBy="#{item.dd}" filterMatchMode="contains">
<p:selectOneMenu id="Dropdown" value="#{item.dd}" required="false"
label="Dropdown" style="width: 90%">
<f:selectItem itemValue="#{null}" itemLabel="" />
<f:selectItems value="#{sampleBean.dropDown.entrySet()}"
var="entry" itemValue="#{entry.value}" itemLabel="#{entry.key}" />
</p:selectOneMenu>
</p:column>
<p:column id="InputTextHeader" headerText="Input Text"
sortBy="#{item.inputText}" filterBy="#{item.inputText}"
filterMatchMode="contains">
<p:inputText id="InputText" value="#{item.inputText}" >
<p:ajax />
</p:inputText>
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
Phase Listener
package sample;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import org.primefaces.component.datatable.DataTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.SampleBean.TableObject;
public class SamplePhaseListener implements PhaseListener {
/**
*
*/
private static final long serialVersionUID = 5273254619684337785L;
private Logger logger = LoggerFactory.getLogger(this.getClass());
public void afterPhase(PhaseEvent event) {
}
public void beforePhase(PhaseEvent event) {
if(event.getPhaseId() == PhaseId.APPLY_REQUEST_VALUES) {
prettyPrint("----------------start of Before "+event.getPhaseId().getName()+"------------------------------", 0);
String tableFilterCount = event.getFacesContext().getExternalContext().getRequestParameterMap().get("tableFilterCount");
if(tableFilterCount != null && "0".equals(tableFilterCount)) {
//backup the previous value first
DataTable table = (DataTable) event.getFacesContext().getViewRoot().findComponent("form:itemTable");
for (int index = 0; index < table.getRowCount(); index++) {
table.setRowIndex(index);
Object rowData = table.getRowData();
if(rowData != null) {
TableObject tableObject = (TableObject) rowData;
logger.info(" before backup to previousDd, dd: {}, previousDd: {}", tableObject.getDd(), tableObject.getPreviousDd());
tableObject.setPreviousDd(tableObject.getDd());
logger.info(" after backup to previousDd, dd: {}, previousDd: {}", tableObject.getDd(), tableObject.getPreviousDd());
}
}
}
prettyPrint("----------------end of Before "+event.getPhaseId().getName()+"------------------------------", 0);
}
if(event.getPhaseId() == PhaseId.RENDER_RESPONSE) {
prettyPrint("----------------start of Before " + event.getPhaseId().getName() + "------------------------------", 0);
String tableFilterCount = event.getFacesContext().getExternalContext().getRequestParameterMap().get("tableFilterCount");
if(tableFilterCount != null && "0".equals(tableFilterCount)) {
//restore the Dd from previous value
DataTable table = (DataTable) event.getFacesContext().getViewRoot().findComponent("form:itemTable");
for (int index = 0; index < table.getRowCount(); index++) {
table.setRowIndex(index);
Object rowData = table.getRowData();
if(rowData != null) {
TableObject tableObject = (TableObject) rowData;
logger.info(" before restore from previousDd, dd: {}, previousDd: {}", tableObject.getDd(), tableObject.getPreviousDd());
tableObject.setDd(tableObject.getPreviousDd());
logger.info(" after restore from previousDd, dd: {}, previousDd: {}", tableObject.getDd(), tableObject.getPreviousDd());
}
}
}
prettyPrint("----------------end of Before "+event.getPhaseId().getName()+"------------------------------", 0);
}
}
public PhaseId getPhaseId() {
return PhaseId.ANY_PHASE;
}
public static final String IDENT = " ";
private void prettyPrint(String str, int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++)
sb.append(IDENT);
sb.append(str + "\n");
logger.trace(sb.toString());
}
}
faces-config.xml
<?xml version='1.0' encoding='UTF-8'?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd"
version="2.3">
<lifecycle>
<phase-listener>sample.SamplePhaseListener</phase-listener>
</lifecycle>
</faces-config>
I'm using Primefaces and spinner component. I want to detect in changEvent method which button of spinner is clicked. I hoped I would get oldValue and newValue but the ValueChangeEvent is null. I am new in Java EE. could some body help me. my English is also not so good.
this is a part of my index.xhtml:
<h:form>
<h:panelGrid columns="2" cellpadding="5" styleClass="ui-grid">
<h:outputLabel for="ajaxSpinner" value="Ajax Spinner: " />
<p:outputPanel>
<p:spinner id="ajaxSpinner" value="#{spinnerView.number5}" >
<p:ajax event="valueChange" update="ajaxSpinnerValue" process="#this" listener="#{spinnerView.changeEvent(event)}" />
</p:spinner>
<h:outputText id="ajaxSpinnerValue" value="#{spinnerView.number5}" style="padding-left: 10px" />
</p:outputPanel>
</h:panelGrid>
</h:form>
and this is Bean-Class
package test.ctrl;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.event.ValueChangeEvent;
import javax.inject.Named;
#Named("spinnerView")
#SessionScoped
public class WebBean implements Serializable{
private int number1;
private int number2;
private int number3;
private int number4;
private int number5;
public int getNumber1() {
return number1;
}
public void setNumber1(int number1) {
this.number1 = number1;
}
public int getNumber2() {
return number2;
}
public void setNumber2(int number2) {
this.number2 = number2;
}
public int getNumber3() {
return number3;
}
public void setNumber3(int number3) {
this.number3 = number3;
}
public int getNumber4() {
return number4;
}
public void setNumber4(int number4) {
this.number4 = number4;
}
public int getNumber5() {
return number5;
}
public void setNumber5(int number5) {
this.number5 = number5;
}
public void callBean(){
System.out.println("Ausgabe" + number5);
}
public void changeEvent(ValueChangeEvent ev){
System.out.println("Ausgabe:"+ev.getOldValue() +"--" +ev.getNewValue());
}
}
I change p:spiner and p:ajax tags as follow:
<p:spinner id="ajaxSpinner" value="#{spinnerView.number5}" valueChangeListener="#{spinnerView.changeEvent}" >
<p:ajax update="#form" process="#this, ajaxSpinner" />
</p:spinner>
What I doing is just an application where the selected option display in the textArea. But Ajax is not working after lending the page after navigation from the main menu on this page. That function only works after using the submit button.
Below is my JSF page code
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
template="/WEB-INF/template.xhtml">
<ui:define name="title">
Ajax Framework - <span class="subitem">Basic</span>
</ui:define>
<ui:define name="description">
This example demonstrates a simple but common usage of posting the form, updating the backend value and displaying the output with ajax.
</ui:define>
<ui:define name="implementation">
<h:form>
<p:panel id="panel" header="Form" style="margin-bottom:10px;">
<p:messages>
<p:autoUpdate />
</p:messages>
<h:panelGrid columns="2" style="margin-bottom:10px" cellpadding="5">
<p:outputLabel for="lazy" value="Lazy:" />
<p:selectOneMenu id="lazy" value="#{selectOneMenuView.option}" lazy="true" style="width:125px">
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems value="#{selectOneMenuView.options}" />
<f:ajax event="change" listener="#{selectOneMenuView.onChange}" execute="#this" render="textarea1"/>
</p:selectOneMenu>
</h:panelGrid>
<p:commandButton value="Submit" update="display" oncomplete="PF('dlg').show()" icon="ui-icon-check" />
<p:dialog header="Values" modal="true" showEffect="bounce" widgetVar="dlg" resizable="false">
<p:panelGrid columns="2" id="display" columnClasses="label,value">
<h:outputText value="Lazy:" />
<h:outputText value="#{selectOneMenuView.option}" />
</p:panelGrid>
</p:dialog>
<h3>AutoResize</h3>
<p:inputTextarea id="textarea1" value="#{selectOneMenuView.inputTextArea}" rows="6" cols="33" />
</p:panel>
</h:form>
</ui:define>
</ui:composition>
And my managed bean is as below
package org.primefaces.showcase.view.input;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.model.SelectItem;
import javax.faces.model.SelectItemGroup;
import org.primefaces.showcase.domain.Theme;
import org.primefaces.showcase.service.ThemeService;
#ManagedBean
public class SelectOneMenuView {
private String console;
private String car;
private List<SelectItem> cars;
private String city;
private Map<String,String> cities = new HashMap<String, String>();
private Theme theme;
private List<Theme> themes;
private String option;
private List<String> options;
private String inputTextArea;
public String getInputTextArea() {
return inputTextArea;
}
public void setInputTextArea(String inputTextArea) {
this.inputTextArea = inputTextArea;
}
#ManagedProperty("#{themeService}")
private ThemeService service;
#PostConstruct
public void init() {
//cars
SelectItemGroup g1 = new SelectItemGroup("German Cars");
g1.setSelectItems(new SelectItem[] {new SelectItem("BMW", "BMW"), new SelectItem("Mercedes", "Mercedes"), new SelectItem("Volkswagen", "Volkswagen")});
SelectItemGroup g2 = new SelectItemGroup("American Cars");
g2.setSelectItems(new SelectItem[] {new SelectItem("Chrysler", "Chrysler"), new SelectItem("GM", "GM"), new SelectItem("Ford", "Ford")});
cars = new ArrayList<SelectItem>();
cars.add(g1);
cars.add(g2);
//cities
cities = new HashMap<String, String>();
cities.put("New York", "New York");
cities.put("London","London");
cities.put("Paris","Paris");
cities.put("Barcelona","Barcelona");
cities.put("Istanbul","Istanbul");
cities.put("Berlin","Berlin");
//themes
themes = service.getThemes();
//options
options = new ArrayList<String>();
for(int i = 0; i < 20; i++) {
options.add("Option " + i);
}
}
public String getConsole() {
return console;
}
public void setConsole(String console) {
this.console = console;
}
public String getCar() {
return car;
}
public void setCar(String car) {
this.car = car;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Theme getTheme() {
return theme;
}
public void setTheme(Theme theme) {
this.theme = theme;
}
public List<SelectItem> getCars() {
return cars;
}
public Map<String, String> getCities() {
return cities;
}
public List<Theme> getThemes() {
return themes;
}
public void setService(ThemeService service) {
this.service = service;
}
public String getOption() {
return option;
}
public void setOption(String option) {
this.option = option;
}
public List<String> getOptions() {
return options;
}
public void setOptions(List<String> options) {
this.options = options;
}
public void onChange(){
this.inputTextArea = this.option;
}
}
May I know why? Can anyone give me some guideline?
I have a class Document for create a Tree with a list of document objects.
public class Document implements Serializable {
private String name;
private String size;
private List<Field> fields;
public Document(String name, String size, String type) {
this.name = name;
this.size = size;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public List<Field> getFields() {
return fields;
}
public void setFields(List<Field> fields) {
this.fields = fields;
}
}
Also I have a Field class for store relevant information in documents
public class Field implements Serializable {
private int fieldIndex;
private String label;
private String value;
private List<Values> list;
public Field() {
}
public int getFieldIndex() {
return fieldIndex;
}
public void setFieldIndex(int fieldIndex) {
this.fieldIndex = fieldIndex;
}
public Field(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public List<Values> getList() {
return list;
}
public void setList(List<Values> list) {
this.list = list;
}
}
My ManagedBean create a tree with some documents and store some data for each document. When i select the tree node, it's show a dynamic form with every field and inputs for enter some value.
#ManagedBean(name="treeSelectionView")
#ViewScoped
public class SelectionView implements Serializable {
private TreeNode root1;
private TreeNode selectedNode;
private String email;
private List<Field> fields;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#PostConstruct
public void init() {
TreeNode root = new DefaultTreeNode(new Document("Files", "-", "Folder"), null);
TreeNode documents = new DefaultTreeNode(new Document("Documents", "-", "Folder"), root);
Field f1=new Field();
Field f2=new Field();
Field f3=new Field();
f1.setLabel("email");
f1.setValue("");
f2.setLabel("doc");
f2.setValue("");
f3.setLabel("otro");
f3.setValue("");
List<Field> fields=new ArrayList<Field>();
fields.add(f1);
fields.add(f2);
fields.add(f3);
List<Field> fields1=new ArrayList<Field>();
f1=new Field();
f2=new Field();
f3=new Field();
f1.setLabel("email");
f1.setValue("");
f2.setLabel("doc");
f2.setValue("");
f3.setLabel("otro");
f3.setValue("");
fields1.add(f1);
fields1.add(f2);
fields1.add(f3);
List<Field> fields2=new ArrayList<Field>();
f1=new Field();
f2=new Field();
f3=new Field();
f1.setLabel("email");
f1.setValue("");
f2.setLabel("doc");
f2.setValue("");
f3.setLabel("otro");
f3.setValue("");
fields2.add(f1);
fields2.add(f2);
fields2.add(f3);
//Documents
Document d1= new Document("Expenses.doc", "30 KB", "Word Document");
Document d2=new Document("Resume.doc", "10 KB", "Word Document");
Document d3=new Document("RefDoc.pages", "40 KB", "Pages Document");
d1.setFields(fields);
d2.setFields(fields1);
d3.setFields(fields2);
TreeNode expenses = new DefaultTreeNode("document",d1, documents);
TreeNode resume = new DefaultTreeNode("document", d2, documents);
TreeNode refdoc = new DefaultTreeNode("document",d3 , documents);
documents.setExpanded(true);
root1 = root;
root1.setExpanded(true);
}
public void onNodeDocumentSelect(NodeSelectEvent nodeSelected) {
// fields=((Document)nodeSelected.getTreeNode().getData()).getFields();
fields=((Document)selectedNode.getData()).getFields();
}
public TreeNode getRoot1() {
return root1;
}
public TreeNode getSelectedNode() {
return selectedNode;
}
public void setSelectedNode(TreeNode selectedNode) {
this.selectedNode = selectedNode;
}
public List<Field> getFields() {
return fields;
}
public void setFields(List<Field> fields) {
this.fields = fields;
}
}
My JSF looks like
<!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: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:head>
<title>Default title</title>
</h:head>
<h:body>
<h:panelGrid columns="2">
<h:form id="treeForm">
<p:panel id="panel22" header="Documents" style="height:400px">
<p:growl id="msgs" showDetail="true" />
<p:tree value="#{treeSelectionView.root1}" var="doc" selectionMode="single" selection="#{treeSelectionView.selectedNode}" >
<p:ajax process="#this" event="select" update=":myForm:dymanicForm" listener="#{treeSelectionView.onNodeDocumentSelect}" />
<p:treeNode expandedIcon="ui-icon-folder-open" collapsedIcon="ui-icon-folder-collapsed">
<h:outputText value="#{doc.name}"/>
</p:treeNode>
<p:treeNode type="document" icon="ui-icon-document" >
<h:outputText value="#{doc.name}" />
</p:treeNode>
</p:tree>
</p:panel>
</h:form>
<h:form id="myForm">
<p:panel id="panel222" header="Info Doccs" style="height:400px">
<p:panel id="dymanicForm" >
<ui:repeat value="#{treeSelectionView.fields}" var="componentMetadata">
<h:panelGrid columns="3">
<h:outputText value="#{componentMetadata.label}"/>:
<h:inputText id="field" value="#{componentMetadata.value}"
required="true" label="#{componentMetadata.label}"/>
<h:message for="field" style="color:red" /></h:panelGrid>
</ui:repeat>
</p:panel>
<h:commandButton value="Submit" action="result" />
</p:panel>
</h:form>
</h:panelGrid>
</h:body>
</html>
When I press the submit button the values are submitted and store in each field, also the validations are fired. But I really need remove the submit button and validate the form when i lost focus every node. By example if i am in the first node validate the form only when i lost focus , but if the form validation fail i need to stay in this node.
Really I appreciate any help you can give me.
Thanks a lot in advance.
I wanted to realize a similar view, and it took me quite some time to figure out.
The trick is not declaring the selection attribute on <p:tree, but just the selectionMode and manage the selection only with the listener, manually.
This causes the selection to be swapped in INVOKE_APPLICATION phase instead of UPDATE_MODEL_VALUES, preserving the right pane references in value expressions.
Furthermore, validation happens before selection swapping and, if fails, the selection swap is prevented.
I think this is exactly what you are looking for:
<h:form>
<p:layout fullPage="false" stateful="false" style="height:400px">
<p:layoutUnit position="center">
<p:tree id="tree" var="data" nodeVar="node" value="#{testTreeBean.root}"
selectionMode="single" dynamic="true" animate="true" highlight="true"
style="border: 0">
<p:ajax event="select" listener="#{testTreeBean.onSelect}" process="#form"
update="#this #form:details" />
<p:ajax event="expand" process="#this" />
<p:ajax event="collapse" process="#this" />
<p:treeNode expandedIcon="ui-icon-folder-open" collapsedIcon="ui-icon-folder-collapsed">
<p:outputPanel id="node">
<h:outputText value="#{data.someText1} - #{data.someText2}" />
</p:outputPanel>
</p:treeNode>
</p:tree>
</p:layoutUnit>
<p:layoutUnit position="east" size="65%" minSize="150">
<p:outputPanel id="details" style="padding: 1em">
<p:panelGrid columns="3" rendered="#{testTreeBean.data != null}">
<p:outputLabel value="someLabel1" for="#next" />
<p:inputText value="#{testTreeBean.data.someText1}" required="true" />
<p:message for="#previous" />
<p:outputLabel value="someLabel2" for="#next" />
<p:inputText value="#{testTreeBean.data.someText2}" required="true" />
<p:message for="#previous" />
</p:panelGrid>
<h:outputText value="please select a node in the left pane"
rendered="#{testTreeBean.data == null}" />
</p:outputPanel>
</p:layoutUnit>
</p:layout>
</h:form>
the bean:
#javax.faces.bean.ManagedBean
#javax.faces.bean.ViewScoped
public class TestTreeBean implements Serializable
{
private static final long serialVersionUID = 1L;
private TreeNode root;
private TreeNode selected;
// build a dummy tree...
#PostConstruct
public void init()
{
root = new DefaultTreeNode();
for(int i = 0; i < 5; i++)
{
SomeData data = new SomeData("node " + i, String.valueOf(System.currentTimeMillis()));
TreeNode node = new DefaultTreeNode(data, root);
for(int j = 0; j < 5; j++)
{
SomeData subData = new SomeData("subNode " + i + "." + j, String.valueOf(System.currentTimeMillis()));
#SuppressWarnings("unused")
TreeNode subNode = new DefaultTreeNode(subData, node);
}
}
}
// handle selection swap manually
public void onSelect(NodeSelectEvent event)
{
if(selected != null)
{
selected.setSelected(false);
}
selected = event.getTreeNode();
if(selected != null)
{
selected.setSelected(true);
}
}
// shortcut for getting the selected node data
public Object getData()
{
return selected == null ? null : selected.getData();
}
public TreeNode getSelected()
{
return selected;
}
public TreeNode getRoot()
{
return root;
}
}
finally, for completeness, the dummy data class:
public class SomeData implements Serializable
{
private String someText1;
private String someText2;
public SomeData()
{
super();
}
public SomeData(String someText1, String someText2)
{
super();
this.someText1 = someText1;
this.someText2 = someText2;
}
public String getSomeText1()
{
return someText1;
}
public void setSomeText1(String someText1)
{
this.someText1 = someText1;
}
public String getSomeText2()
{
return someText2;
}
public void setSomeText2(String someText2)
{
this.someText2 = someText2;
}
}
Happy gardening :)
I don't know if I complicate things so much but I can't figure out how to update a single row from my datatable, here's my code:
listado.xhtml
<?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://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<h:dataTable border="1" value="#{guardarBean.listaCustomer}" var="o">
<h:column>
<f:facet name="header">Customer ID</f:facet>
#{o.customerId}
</h:column>
<h:column>
<f:facet name="header">Discount Code</f:facet>
#{o.discountCode.discountCode}
</h:column>
<h:column>
<f:facet name="header">Zip</f:facet>
#{o.zip.zipCode}
</h:column>
<h:column>
<f:facet name="header">Name</f:facet>
<h:inputText value="#{o.name}" rendered="#{guardarBean.isEditable}"/>
<h:outputText value="#{o.name}" rendered="#{not guardarBean.isEditable}"/>
</h:column>
<h:column>
<f:facet name="header">Address 1</f:facet>
<h:outputText value="#{o.addressline1}" />
</h:column>
<h:column>
<f:facet name="header">Address 2</f:facet>
#{o.addressline2}
</h:column>
<h:column>
<f:facet name="header">City</f:facet>
#{o.city}
</h:column>
<h:column>
<f:facet name="header">State</f:facet>
#{o.state}
</h:column>
<h:column>
<f:facet name="header">Phone</f:facet>
#{o.phone}
</h:column>
<h:column>
<f:facet name="header">Fax</f:facet>
#{o.fax}
</h:column>
<h:column>
<f:facet name="header">Email</f:facet>
#{o.email}
</h:column>
<h:column>
<f:facet name="header">Credit Limit</f:facet>
#{o.creditLimit}
</h:column>
<h:column>
<f:facet name="header">Edit</f:facet>
<h:commandButton action="#{guardarBean.editAction()}" value="Editar" />
</h:column>
<h:column>
<f:facet name="header">Save</f:facet>
<h:commandButton value="Save Changes" action="#{guardarBean.editar(o)}">
<f:ajax render="#form" execute="#form"/>
</h:commandButton>
</h:column>
<h:column>
<f:facet name="header">Delete</f:facet>
<h:commandButton action="#{guardarBean.borrar(o)}" value="Borrar">
<f:ajax render="#form" />
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
</h:body>
</html>
guardarBean.java
import app.dao.CustomerFacadeLocal;
import app.dao.DiscountCodeFacadeLocal;
import app.dao.MicroMarketFacadeLocal;
import app.entity.Customer;
import app.entity.DiscountCode;
import app.entity.MicroMarket;
import java.util.List;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
#ManagedBean
#RequestScoped
public class GuardarBean {
#EJB
private CustomerFacadeLocal customerFacade1;
#EJB
private MicroMarketFacadeLocal microFacade;
#EJB
private DiscountCodeFacadeLocal discFacade;
public Integer getId(){
return id;
}
public void setId(Integer id){
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress1() {
return address1;
}
public void setAddress1(String address1) {
this.address1 = address1;
}
public String getAddress2() {
return address2;
}
public void setAddress2(String address2) {
this.address2 = address2;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getFax() {
return fax;
}
public void setFax(String fax) {
this.fax = fax;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getCredit_limit() {
return credit_limit;
}
public void setCredit_limit(Integer credit_limit) {
this.credit_limit = credit_limit;
}
public String getDiscount() {
return discount;
}
public void setDiscount(String discount) {
this.discount = discount;
}
public String getZip() {
return zip;
}
public void setZip(String zip) {
this.zip = zip;
}
private Integer id;
private String name;
private String address1;
private String address2;
private String city;
private String state;
private String phone;
private String fax;
private String email;
private Integer credit_limit;
private String discount;
private String zip;
private boolean isEditable;
private List<DiscountCode> listaDiscount;
private List<Customer> listaCustomer;
public List<Customer> getListaCustomer() {
//FacesContext.getCurrentInstance().getExternalContext().getSession(true);
listaCustomer =(List<Customer>)customerFacade1.findAll();
return listaCustomer;
}
public void setListaCustomer(List<Customer> listaCustomer) {
this.listaCustomer = listaCustomer;
}
public List<DiscountCode> getListaDiscount() {
listaDiscount = (List<DiscountCode>)discFacade.findAll();
return listaDiscount;
}
public void setListaDiscount(List<DiscountCode> listaDiscount) {
this.listaDiscount = listaDiscount;
}
/**
* Creates a new instance of GuardarBean
*/
public GuardarBean() {
}
public void insertar(){
Customer customer = new Customer();
DiscountCode dc = discFacade.find(discount.toCharArray()[0]);
customer.setDiscountCode(dc);
MicroMarket mm = microFacade.find(zip);
customer.setZip(mm);
customer.setName(name);
customer.setCustomerId(id);
customer.setAddressline1(address1);
customer.setAddressline2(address2);
customer.setCity(city);
customer.setCreditLimit(credit_limit);
customer.setEmail(email);
customer.setFax(fax);
customer.setPhone(phone);
customer.setState(state);
customerFacade1.create(customer);
}
public boolean isIsEditable() {
return isEditable;
}
public void setIsEditable(boolean isEditable) {
this.isEditable = isEditable;
}
public void editAction() {
setIsEditable(true);
}
public void editar(Customer customer){
customerFacade1.edit(customer);
setIsEditable(false);
}
public void borrar(Customer c)
{
customerFacade1.remove(c);
}
}
It's simply, via "getListaCustomer" retrieve a list of customers that it's render in datatable, this datatable has an edit column that's when is pressed calls editAction() that set isEditable variable to true for show an inputText for modify the name value in his correspondent column as you can see, the value it's binding to his attribute of the element of the list so when I click in save changes button calls editar function but debugging I can see that customer passed as parameter to this functions has no value in set attribute so it's not doing properly well the caption of data in order to set up in his attribute, what I'm doing wrong?
Regards!
Replacing #RequestScoped with #ViewScoped does the trick.
Consult this thread, precious as it is, it includes a link toward a good tuto (of the immense BalusC ) about Managed Bean Scopes, here.
Best of luck :).