JSF2 "f:ajax render" renders more than the specified id - java

I've searched and tried various things from around here and the web; prependId, using full id paths (:form:panelid:componentid kinda thing), and others.
I'm still confused. I'm still a JSF noob :)
My problem is that whatever I specify in the f:ajax render part isn't the only parts the get "executed". What I mean is, the id specified in render won't get rerendered on screen, but the value of that component do get called.
So:
inputText's f:ajax render=outA event=blur
when blur happens, outA's getter is called and it rerendered, but also the getter of other components are called, but they're not rerendered.
Specifically, in light of the listed code below:
A) When val1 loses focus, it's blur event fires, which has it call getValue1() and rerender outval1. Happy. But, getStuff() is ALSO called (it happens for the other blur and btnCalc also) BUT the result from getStuff() is NOT rendered to tblStuff dataTable.
Why?
How can I fix it, so that on the blur event, only the getters relevent to the render=".." component is executed?
Should I maybe use different sections?
B) when the refresh button is clicked, then it will call getStuff AGAIN, and now show the new dataTable / ie that new data with ALL THE MANY ValueTO's that was added during the blur events and the btnReload click event.
C) For any one event named in A, the getStuff method is called exactly 8 times. ie, click inside inputbox, click outside input box, getStuff() * 8.
Yet, getValue1 is called only twice?
D) Any good JSF2 books out there?
Here is the page:
<?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:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Stuff</title>
</h:head>
<h:body>
<h:form id="frmTrxMain" prependId="true">
<h1>
Stuff
</h1>
<h:dataTable title="Stuff" id="tblStuff" var="s" value="#{bean.stuff}" border="1">
<h:column>
<f:facet name="header">
<h:outputText value="ID" />
</f:facet>
<h:outputText value="#{s.id}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Name" />
</f:facet>
<h:outputText value="#{s.name}" />
</h:column>
</h:dataTable>
<h:outputText value="No stuff to display" rendered="#{empty bean.stuff}"/>
<h:commandButton value="Refresh" id="btnReload">
<f:ajax render="tblStuff" event="click"/>
</h:commandButton>
<hr/>
<h:panelGrid columns="3" id="pnlTwo">
<h:outputLabel value="Value1"/>
<h:inputText value="#{bean.value1}" id="val1">
<f:ajax event="blur" render="outVal1"/>
</h:inputText>
<h:outputText id="outVal1" value="Entered: #{bean.value1}" />
<h:outputLabel value="Value2"/>
<h:inputText value="#{bean.value2}" id="val2">
<f:ajax event="blur" render="outVal2"/>
</h:inputText>
<h:outputText id="outVal2" value="Entered: #{bean.value2}" />
<h:commandButton value="Calc" id="btnCalc">
<f:ajax event="click" render="outSum"/>
</h:commandButton>
</h:panelGrid>
<h:outputLabel id="outSum" value="#{bean.sum}"/>
</h:form>
</h:body>
</html>
And the backing bean:
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name = "bean")
#SessionScoped
public class TestStuffBean {
private int id=1;
private String name="a";
//test.xhtml
private String value1;
private String value2;
private List<TestVO> stuff = new ArrayList<TestVO>();
public String getValue1() {
return value1;
}
public void setValue1(String value1) {
this.value1 = value1;
}
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
public String getSum() {
String result = "";
int sum;
try {
sum = Integer.parseInt(value1) + Integer.parseInt(value2);
result = Integer.toString(sum);
} catch (NumberFormatException e) {
result = "Enter two integers";
}
return result;
}
public List<TestVO> getStuff() {
//the VO is just a POJO with a contructor that takes
//two strings and a getter/setter for each id and name
stuff.add(new TestVO(Integer.toString(id), name+id));
id++;
return stuff;
}
}

I'm not a JSF 2 expert since we're still using 1.2 but I guess they have the same properties here: the getters are called often, e.g. when reconstrucing the view in the restore-view phase. Thus you can't rely on the getters only being called for the actually rendered part. In fact, you shouldn't do any costly operations (like db access) in your getters - in most cases you don't know how often they're actually called in one cycle.
Especially your getStuff() method should be changed, it's also almost always bad design to have a getter cause side effects like something being added to an internal list, like in this case.
Edit: To clarify the comment on getters:
Normally a getter should not do costly operations, since you don't know how often JSF will call them.
Since you still have to get some data from some source (like a database) you might provide methods to only do that (like loadDataFromDB()) and fill some data structure in the managed bean. The getter might then just deliver that data structure.
You might add a check for the data structure not being initialized and if not call the load method in the getter, but I'd only use that as a last option. Generally you should be able to separately call the load method, e.g. by clicking a refresh button or when navigating to the page - that's what we do.

Related

JSF page not reloading on form action

Please read to the end, there are many EDITS I have this piece of JSF code:
<h:form>
<h:dataTable class="table-striped" var="_product"
value="#{productManager.products}"
border="1"
binding="#{productManager.table}">
<h:column>
<f:facet name="header">Product</f:facet>
#{_product.name}
</h:column>
<h:column>
<f:facet name="header">Available Units</f:facet>
#{_product.stock}
</h:column>
<h:column>
<f:facet name="header">Category</f:facet>
#{_product.category}
</h:column>
<h:column>
<f:facet name="header">Price</f:facet>
#{_product.price}
</h:column>
<h:column>
<f:facet name="header">Description</f:facet>
#{_product.description}
</h:column>
<h:column>
<f:facet name="header">Select</f:facet>
<h:commandButton class="btn btn-primary" value="Select"
action="#{productManager.selectProduct}"/>
</h:column>
</h:dataTable>
</h:form>
<h:form>
<h:outputLabel for="productName">Selected Product: </h:outputLabel>
<h:inputText value="#{productManager.selectedDesiredCategory}"/>
<h:commandButton value="Filter category" action="#{productManager.filterProductsByCategory}"/>
<h:outputText id="productName" value="#{productManager.selectedName}"/><br/>
<h:outputLabel for="units">Units: </h:outputLabel>
<h:inputText id="units" value="#{productManager.selectedUnits}"/>
<h:commandButton value="Add to basket" action="#{productManager.addToBasket(accountManager.username)}"/><br/>
<h:outputText rendered="#{productManager.availableMessages}"
value="#{productManager.message}"/>
</h:form>
The #{productManager.filterProductsByCategory} commandbutton redirects to this java method:
public void filterProductsByCategory() {
this.products = controller.obtainProductListByCategory(selectedDesiredCategory);
showMessage("Filtered by selected category");
}
Here I update the content of the products list with the new set of filtered-by-category products to display them in the view. The thing is the page is not reloading to display the new content. How is this achieved?
EDIT: The showMessage method is actually displaying in the view, so the page IS reloading, but for some reason the table is not updating. Maybe it's a problem with the data the query is returning, I'm actually researching.
EDIT: The query is returning good results, as my debugging process confirmed, but the webpage is not reloading the data properly in the table.
EDIT: I found out something really weird. This is the code the JSF page is referencing to:
public void filterProductsByCategory()
{
filtered = true;
products = controller.obtainProductListByCategory(selectedDesiredCategory);
showMessage("Filtered by selected category");
}
I'm now using a boolean value to actually know when I have to deliver a filtered list (See why in the code below) This is the getter of the products list:
public List<Product> getProducts()
{
if(filtered)
{
filtered = false;
return products;
}
products = controller.obtainProductList();
return products;
}
Here if it's true it should just send the actual filtered products variable. But for some reason it's looping again and again inside the method (even after the return statement inside the if) and sending all the products to the view again. Why is this even happening?
By default, JSF calls the getter methods as much as they're used in the view. For example, for your List<Product> products field and its respective getter, if #{productManager.products appears twice in your view i.e. in the Facelets code, then the getter will be executed twice as well. For this reason, getter and setter methods in managed bean should be as clean as possible and should not contain any business logic involved.
Basically, you should retrieve the product list from database once, after creating the managed bean and before the view render time. To achieve this, you can use #PostConstruct annotation to decorate a void method that will be executed after the bean is created.
In code:
#ManagedBean
#ViewScoped
public class ProductManager {
private List<Product> products;
#PostConstruct
public void init() { //you can change the method name
//if you manually handle the controller, initialize it here
//otherwise, let it be injected by EJB, Spring, CDI
//or whichever framework you're working with
products = controller.obtainProductList();
}
public List<Product> getProducts() {
//plain getter, as simple as this
//no business logic AT ALL
return this.products;
}
public void filterProductsByCategory() {
filtered = true;
products = controller.obtainProductListByCategory(selectedDesiredCategory);
//I guess this method logs a message or something...
showMessage("Filtered by selected category");
}
}
More info
Why JSF calls getters multiple times
Why use #PostConstruct?

h:inputText inside a h:dataTable does not preserve its state after clicking a commandButton with immediate true

I need to display some entities in a h:dataTable that must be editable. The user can add and remove entities from this table. The problem is that when I add an entity clicking the button "Add" the state of what the user typed is gone.
I'm running Mojarra 2.1.7-jbossorg-1 (20120227-1401)
This is the first time the view is displayed, as you can see the dataTable is empty:
Then I click add and the following is showed:
I typed some values in the inputs:
I clicked "Add" again and as you can see the values that I typed of the first row are gone:
I need to be able to keep the state of the rows until I finish the edition and that's until I click the button "Save".
I also tried with rowStatePreserved="true" attribute of the h:dataTable and this is what happens:
Just after I typed something in the first row and I click add:
The first row state is preserved but the second row added has the same values as the first one even though I haven't typed anything in it yet.
Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:oms="http://aom.org/oms"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Testing</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</h:head>
<h:body>
<h:form id="myForm" prependId="false">
<h:dataTable value="#{testingBean.persons}" var="person" border="1" rowStatePreserved="true">
<h:column>
<f:facet name="header">Name</f:facet>
<h:inputText value="#{person.name}"/>
</h:column>
<h:column>
<f:facet name="header">Age</f:facet>
<h:inputText value="#{person.age}"/>
</h:column>
<h:column>
<h:commandButton action="#{testingBean.remove(person)}" value="Remove" immediate="true"/>
</h:column>
</h:dataTable>
<h:commandButton action="#{testingBean.add()}" value="Add" immediate="true"/>
<h:commandButton action="#{testingBean.save()}" value="Save" />
</h:form>
</h:body>
</html>
TestingBean.java:
package org.aom.oms.controller;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.inject.Model;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class TestingBean {
private List<Person> persons = new ArrayList<TestingBean.Person>();
public List<Person> getPersons() {
return persons;
}
public void setPersons(List<Person> persons) {
this.persons = persons;
}
//Inner class for testing purpose
public class Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
public void save() {
System.out.println("Saving...");
//myRepository.save(persons);
}
public void add() {
persons.add(new Person());
}
public void remove(Person person) {
persons.remove(person);
}
}
Instead of using h:dataTable use Tomahawk t:datatable
The MyFacesDataTable extends the standard JSF DataTable by two
important features:
Possiblity to save the state of the DataModel.
Support for clickable sort headers (see SortHeader component).
These attributes let you do what you want:
preserveRowStates (boolean): Indicates whether the state for each
row should not be discarded before the datatable is rendered again.
Setting this to true might be hepful if an input component inside the
datatable has no valuebinding and the value entered in there should be
displayed again. This will only work reliable if the datamodel of the
datatable did not change either by sorting, removing or adding rows.
Default: false
forceIdIndexFormula (String): formula that overrides the default
row index in the construction of table's body components. Example : #{myRowVar.key} > Warning, the EL should evaluate to a unique value for each row !

how can I call a method from a subtable from Primefaces?

I am using primefaces for not so long and Ive found that I cant use a <p:commandButton /> because it just can't reach the method, the method is ok, I tried it out of the table (and the subtable) and it works perfectly there (everything is inside a form) , the problem is that I need the user to be able to select all the subtable, so, I thought maybe with a button that could be possible, but seems like subtable doesn't allow that, any other way I can do this? or maybe I have to use another way for call my method from a subtable, anybody knows about it?
Thanks
some of my code
<h:form>
<p:messages id="messages" showDetail="true" autoUpdate="true" closable="true" />
<p:dataTable id="case" var="ticket" value="#{CaseBean.selectedCase.tickets}">
<p:columnGroup>
<p:row>
<p:column> Action:</p:column>
<p:column>
<!-- This doesn't work, removed. -->
<p:commandButton value="Aprove" action="#{CaseBean.acept()}">
</p:commandButton>
</p:column>
</p:row>
</p:columnGroup>
<p:subTable var="detail" value="#{ticket.detail}">
<f:facet name="header">
Resume:
</f:facet>
<!-- some data... -->
<p:column>
<!-- doesn't work either -->
<p:commandButton value="Aprove" action="#{CaseBean.aceptTicket()}">
</p:commandButton>
</p:column>
<!-- show my data -->
The table works perfectly, it shows all the data, the log files doesn't show any error, so, when I tried to write my commandButton out of the table it worked perfectly, if I cant write it inside a subtable its ok, but , how could I write it in the table? it doesn't show up there either.
you welcome :)
But if i was you I wouldn't use subtables, Ill think for another solution..maybe Ill do it this way, ill use two different data tables, the first contains the parent list and the second one contains the child list elements, and every selection made triggers an update of the second table...I tried it on my IDE and it works just fine
<h:form id="form">
<p:dataTable var="cas" value="#{beanCase.myListOfCase}"
selection="#{beanCase.selectedCase}" rowKey="#{cas.idCase}"
selectionMode="single">
<p:ajax event="rowSelect" update=":form:TicketTable" />
<p:column headerText="Id Case">
<h:outputText value="#{cas.idCase}" />
</p:column>
<p:column headerText="Case Name ">
<h:outputText value="#{cas.caseName}" />
</p:column>
<p:column headerText="Case Detail">
<h:outputText value="#{cas.caseDetail}" />
</p:column>
<p:column headerText="Action">
<p:commandButton value="Accept Case" update=":form:TicketTable"></p:commandButton>
</p:column>
</p:dataTable>
<p:dataTable id="TicketTable" var="ticket"
value="#{beanCase.selectedCase.tickets}">
<p:column headerText="Ticket Number">
<h:outputText value="#{ticket.idTicket}" />
</p:column>
<p:column headerText="Ticket Details">
<h:outputText value="#{ticket.labelTicket}" />
</p:column>
<p:column headerText="show">
<h:outputText value="#{ticket.show}" />
</p:column>
<p:column headerText="this show is brought to you by">
<h:outputText value="#{ticket.sponsor}" />
</p:column>
<p:column headerText="Make a Reservation">
<p:commandButton value="Buy" action="#{beanCase.buyTicket()}">
<f:setPropertyActionListener value="#{ticket}"
target="#{beanCase.selectedTicket}" />
</p:commandButton>
</p:column>
</p:dataTable>
before that you must create the data model classes for the Case and ticket
public class CaseDataModel extends ListDataModel<Case> implements
SelectableDataModel<Case> {
CaseDAO caseDAO = new CaseDAO();
public CaseDataModel() {
}
public CaseDataModel(List<Case> cases) {
super(cases);
}
#Override
public Case getRowData(String arg0) {
List<Case> listOfMyObjet = (List<Case>) caseDAO.findAll();
for (Case obj : listOfMyObjet) {
if (String.valueOf(obj.getIdCase()).equals(arg0))
;
return obj;
}
return null;
}
#Override
public String getRowKey(Case arg0) {
return String.valueOf(arg0.getIdCase());
}
}
The first columnGroup is not rendered because in your first row the number of columns is 2, one for "action" and the other for the commandButton while in your subtable you just used two rows one for "Resume" and other contains only one Column for the other commandButton.
The number of columns should be the same in every row, so you must use colspan or rowspan to make sure of that.
As for the rest using a DataTable will do the job, I didn't understand what you wanna do exactly but I all assume that you want to select myObject from displayed list of objects within a dataTable. So in order to achieve that, the UidataTable must return an object to the backed Bean.
public class myObjectDataModel extends ListDataModel<myObject> implements SelectableDataModel<myObject> {
public myObjectDataModel() {
}
public myObjectDataModel(List<myObject> data) {
super(data);
}
#Override
public myObject getRowData(String rowKey) {
List<myObject> listOfMyObjet = (List<myObject>) yourDao.getListOfmyOjects();//get your list
for(myObject obj : listOfMyObjet) {
if(obj.getIdObject().equals(rowKey))
return obj;
}
return null;
}
#Override
public Object getRowKey(myObject obj) {
return obj.getIdObject();
}
}
The backed bean:
public class tableBean {
private List<myObject> _Objects;
private myObjectDataModel myListOfObjects;
private myObject selectedObject;
//getters and setters
public tableBean(){
myObjectDataModel = new myObjectDataModel(_Objects);
}
//...
}
xhtml:
<p:dataTable id="table" var="case"
value="#{tableBean.myObjectDataModel}"
selection="#{tableBean.selectedObject}" selectionMode="single"
rowKey="#{case.IdObject}">
<p:column>
<p:commandButton value="
Aprove" action="#{tableBean.someMethod()}">
</p:commandButton>
</p:column>
</p:dataTable>
and make sure to use Ajax — commandButton update attribute, or <p:ajax> — to refresh your UI.
Try removing the p:columnGroup from your JSF page. You don't need it for this (and this might be the cause of your problem). Think of it like this: a table exists of rows and rows exist of columns. ;-)
The #{CaseBean} has got to be in the view scope in order to get this to work, or if you want to keep it request scoped, the #{CaseBean.selectedCase.tickets} has to prepared in the (post)constructor on some request parameters so that it's exactly the same as it was during displaying the table.
When the form is submitted, JSF will namely reiterate over the table in order to find the command component responsible for the action. However, if the bean is request scoped and the value behind #{CaseBean.selectedCase} or #{CaseBean.selectedCase.tickets} is not the same as it was during displaying the table, then JSF won't be able to identify the button which invoked the action.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 4 applies to you

How to update the property member variable of a managed bean?

I have a member variable in a managed bean, and this member variable is tied to the component in XHTML with a getter and setter. If I set the member variable in a function call, when the getter of this member variable is trigger, this member variable will still hold the old value. May I know how could I update this member variable so that the component could get the latest updated value?
The manage bean:
#ManagedBean(name = "myBean")
#SessionScoped
public class MyBean {
public boolean show = false;
/** getter and setter **/
public void theFunc() {
this.show = true;
}
}
XHTML code
<h:panelGroup id="Panel_1" rendered="#{myBean.show == true}">
...
Some rubbish here
...
</h:panelGroup>
<h:panelGroup id="Panel_2">
<h:commandLink action="#{myBean.doFunc}">
<f:ajax event="action" render="Panel_1"/>
<h:outputText value="XX" />
</h:commandLink>
</h:panelGroup>
From this sample, the show variable is showing false even though theFunc() has already set to true.
Update on 06 Oct 2012
I have remove commandButton and replace with commandLink, I think it should be fine in term of usage.
Change your methods return type and name if you want it to be invoked.
Change this
public void theFunc() {
this.show = true;
}
to this
public String doFunc() {
this.show = true;
return null;
}
otherwise this action can not work.
<h:commandLink action="#{myBean.doFunc}">
then update parent of your panel like this
<h:panelGroup id="parentPanelGroupId">
<h:panelGroup id="Panel_1" rendered="#{myBean.show}">
...
Some rubbish here
...
</h:panelGroup>
</h:panelGroup>
<h:panelGroup id="Panel_2">
<h:commandLink action="#{myBean.doFunc}">
<f:ajax render="parentPanelGroupId"/>
<h:outputText value="SHOW/HIDE PANEL 1" />
</h:commandLink>
</h:panelGroup>
NOTE:
use
rendered="#{myBean.show}"
instead of
rendered="#{myBean.show == true}"
Try this way:
<h:panelGroup id="toUpdate">
<h:panelGroup id="Panel_1" rendered="#{myBean.show}">
...
</h:panelGroup>
</h:panelGroup>
<h:commandButton action="#{theBean.doCalculation}">
<f:ajax render="toUpdate" />
</h:commandButton>
There are 2 things to note:
You need to wrap <h:panelGroup id="Panel_1"> inside another <h:panelGroup> or something eles which is always rendered. Otherwise, if the show variable is initially false, the ajax update may not work since JSF renderer cannot find the the component with id="Panel_1" when you use <f:ajax render="Panel_1" />.
rendered="#{myBean.show}" is good enough :P. Since show is a boolean variable, you don't need rendered="#{myBean.show == true}".

JSF : able to do mass update but unable to update a single row in a datatable

I have a simple data object: Car. I am showing the properties of Car objects in a JSF datatable. If i display the properties using inputText tags, i am able to get the modified values in the managed bean. However i just want a single row editable. So have placed a edit button in a separate column and inputText and outputText for every property of Car. the edit button just toggles the rendering of inputText and outputText. Plus i placed a update button in a separate column which is used to save the updated values. However on clicking the update button, i still get the old values instead of the modified values. Here is the complete code:
public class Car {
int id;
String brand;
String color;
public Car(int id, String brand, String color) {
this.id = id;
this.brand = brand;
this.color = color;
}
//getters and setters of id, brand, color
}
Here is the managed bean:
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UIData;
#ManagedBean(name = "CarTree")
#RequestScoped
public class CarTree {
int editableRowId;
List<Car> carList;
private UIData myTable;
public CarTree() {
carList = new ArrayList<Car>();
carList.add(new Car(1, "jaguar", "grey"));
carList.add(new Car(2, "ferari", "red"));
carList.add(new Car(3, "camri", "steel"));
}
public String update() {
System.out.println("updating...");
//below statments print old values, was expecting modified values
System.out.println("new car brand is:" + ((Car) myTable.getRowData()).brand);
System.out.println("new car color is:" + ((Car) myTable.getRowData()).color);
//how to get modified row values in this method??
return null;
}
public int getEditableRowId() {
return editableRowId;
}
public void setEditableRowId(int editableRowId) {
this.editableRowId = editableRowId;
}
public UIData getMyTable() {
return myTable;
}
public void setMyTable(UIData myTable) {
this.myTable = myTable;
}
public List<Car> getCars() {
return carList;
}
public void setCars(List<Car> carList) {
this.carList = carList;
}
}
here is the JSF 2 page:
<?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 id="carForm" prependId="false">
<h:dataTable id="dt" binding="#{CarTree.myTable}" value="#{CarTree.cars}" var="car" >
<h:column>
<h:outputText value="#{car.id}" />
</h:column>
<h:column>
<h:outputText value="#{car.brand}" rendered="#{CarTree.editableRowId != car.id}"/>
<h:inputText value="#{car.brand}" rendered="#{CarTree.editableRowId == car.id}"/>
</h:column>
<h:column>
<h:outputText value="#{car.color}" rendered="#{CarTree.editableRowId != car.id}"/>
<h:inputText value="#{car.color}" rendered="#{CarTree.editableRowId == car.id}"/>
</h:column>
<h:column>
<h:commandButton value="edit">
<f:setPropertyActionListener target="#{CarTree.editableRowId}" value="#{car.id}" />
</h:commandButton>
</h:column>
<h:column>
<h:commandButton value="update" action="#{CarTree.update}"/>
</h:column>
</h:dataTable>
</h:form>
</h:body>
</html>
However if i just keep the inputText tags and remove the rendered attributes, i get the modified values in the update method. How can i get the modified values for the single row edit?
I get the modified values in update method when i change the scope from request to session. Is there a better approach instead of using SessionScoped? SessionScoped == Server Memory,that's why i want to avoid it.
Rant(or frustration?): Really if there was something similar to ObjectDataSource of asp.net, it would have been so much easier. Even for moderate work with datatable, we have to lookup lifecycle issues. Whereas in asp.net ObjectDataSource + ListView combo is enough for most of data + UI related matters plus hardly we have to lookup lifecycle of a control(Infact, asp.net guys hardly ever lookup the docs). Why cant the base JSF specification provide for a control capable of CRUD operations out of the box with perhaps lazy loading capability. isn't it required for each and every application?
JSF has already updated the model values for you. Just access it the usual way.
public String update() {
for (Car car : carList) {
if (/* this item was set to editmode */) {
System.out.println("new car brand is:" + car.brand);
System.out.println("new car color is:" + car.color);
}
}
return null;
}
By the way, making model properties non-private is a bad idea. You should make them private and access them by getters/setters. I.e. car.getBrand(), car.getColor() and so on.

Categories