How to maintain/save row values when generating a new row? - jsf

i have the following bean:
public class MyBean {
public ArrayList<ReportRow> getReportRows()
{
return reportRows;
}
private final ArrayList<ReportRow> reportRows =
new ArrayList<ReportRow>(Arrays.asList(
new ReportRow("","")
));
public ArrayList<ReportRow> getOrderList() {
return reportRows;
}
public String addAction() {
ReportRow row = new ReportRow("", "");
reportRows.add(row);
return null;
}
public class ReportRow{
String reportColumnName;
String reportColumnDesc;
public ReportRow(String reportColumnName,String reportColumnDesc) {
this.reportColumnName=reportColumnName;
this.reportColumnDesc=reportColumnDesc;
}
public String getReportColumnName()
{
return reportColumnName;
}
public void setReportColumnName(String reportColumnName)
{
this.reportColumnName = reportColumnName;
}
public String getReportColumnDesc()
{
return reportColumnDesc;
}
public void setReportColumnDesc(String reportColumnDesc)
{
this.reportColumnDesc = reportColumnDesc;
}
}
}
jsf page:
<t:dataTable value="#{myBean.reportRows}" var="o"
id="reportColumnsTable" styleClass="standardTable" headerClass="standardTable_Header"
rowStyleClass="#{myBean.viewDelayedRsd}"
>
<h:column>
<t:outputLabel value="Column name:"></t:outputLabel>
<t:inputText id="ReportColumnName" value="#{o.reportColumnName}" required="true">
</t:inputText>
</h:column>
<h:column>
<t:outputLabel value="Column Desc:"></t:outputLabel>
<t:inputText id="ReportColumnDesc" value="#{o.reportColumnDesc}" >
</t:inputText>
</h:column>
<h:column>
<h:outputLink value="#add"><h:outputText value="Add"/>
<a4j:support ajaxSingle="true" event="onclick" action="#{rprtBean.addAction}"
reRender="reportColumnsTable,msgPanel" />
</h:outputLink>
</h:column>
</t:dataTable>
problem is that when i click on add, it generates a new row, and clear the old one, and i want to maintain the values of old row, any ideas ?

You're using a <h:outputLink> instead of a <h:commandLink>. The <h:outputLink> doesn't submit the form at all, it fires a plain GET request. The <a4j:support> won't work properly inside a <h:outputLink>. Replace it by a <h:commandLink>:
<h:commandLink value="Add" action="#{rprtBean.addAction}">
<a4j:support reRender="reportColumnsTable,msgPanel" ajaxSingle="true" />
</h:commandLink>
Then, you need to ensure that you preserve the data model for subsequent request in case that your bean is request scoped. There are several ways to achieve this:
Set either Tomahawk datatable's preserveDataModel to true:
<t:dataTable preserveDataModel="true">
Or save the bean state in the view scope. Add the following tag somewhere in the page:
<t:saveState value="#{myBean}" />
or since you're also using RichFaces/Ajax4jsf:
<a4j:keepAlive beanName="myBean" />

i just used the a4j command link and everything worked fine.

Related

jsf inputText only displayed value when is readonly true or outputText

I have a h:inputText with valueChangeListener, when the user type some code another h:inputText display data from MySQL about that code, the valueChangeListener works but the second h:inputText not displayed the value and only do it when I set the readonly attribute or I change the component to h:outputText
my facelets page is:
<h:form id="idFacturacion">
<rich:panel>
<f:facet name="header">
<h:outputText value="FACTURACION AL CLIENTE" />
</f:facet>
<h:panelGrid columns="4">
<h:outputText value="Cedula: " />
<h:inputText value="#{facturaBean.encFactura.cedula}" onchange="submit();" valueChangeListener="#{facturaBean.processValueChange}" />
<h:outputText value="Nombre: " />
<h:inputText value="#{facturaBean.encFactura.nombre_cli}" />
</h:panelGrid>
</rich:panel>
</h:form>
facturaBean is:
#ManagedBean
#SessionScoped
public class FacturaBean {
private EncFactura encFactura = new EncFactura();
//getter and setter
public void processValueChange(ValueChangeEvent event){
String ced = event.getNewValue().toString();
try{
//do the database thing
if(resultSet.next()){
encFactura.setNombre_cli(resultSet.getString("nombre_cli"));
}else{
encFactura.setNombre_cli("");
}
}catch(SQLException error){
facesContext.addMessage(null, new FacesMessage("Hubo un error SQL."));
}
}
}
Please see
Change inputText value from listener method… and
Possible to execute `valueChangeListener` for `p:inputText` without hitting `enter` key?
May I suggest using ajax?
Here is a primefaces example but you could apply to richfaces..
<h:inputText value="#{facturaBean.stringOne}" >
<p:ajax event="change" listener="#{facturaBean.processValueChange}" update="strTwo"/> </h:inputText> <h:outputText value="Nombre: " />
<h:inputText id="strTwo" value="#{facturaBean.stringTwo}" />
</h:panelGrid>
private String stringOne= "";
private String stringTwo= "";
public void processValueChange(){
stringTwo = stringOne;
}
With getters etc.. basically on change, fires off to ajax, you do your database call etc, then it returns the response and updates your other input field, it's a much cleaner way than trying to submit forms etc..
Also are you sure you want session scope?

values not getting passed from datatable to dialog box

<p:column>
<p:commandButton id="selectButton" update="#(form)" oncomplete="userDialog.show()" icon="ui-icon-search" title="View">
<f:setPropertyActionListener value="#{book}" target="#{CreateBookBean.selectedUser}" />
</p:commandButton>
</p:column>
</p:dataTable>
</p:outputPanel>
<p:dialog header="User Detail" modal="true" widgetVar="userDialog" width="200" height="175">
<h:panelGrid columns="2" cellpadding="5">
<h:outputLabel for="fname" value="First Name: " />
<h:outputText id="fname" value="#{CreateBookBean.selectedUser.fname}" />
<h:outputLabel for="lname" value="Last Name: " />
<h:outputText id="lname" value="#{CreateBookBean.selectedUser.lname}" />
<h:outputLabel for="mobileno" value="mobile no: " />
<h:outputText id="mobileno" value="#{CreateBookBean.selectedUser.mobileno}" />
</h:panelGrid>
</p:dialog>
i came across this example recently.
the datatable is properly getting updated with the values i enter. but when i want to display it in the dialog box its not displaying anything.
and i actually don understand why value="#{CreateBookBean.selectedUser.fname}" is used instead of value="#{CreateBookBean.fname}".
here is my java code
public class CreateBookBean {
private Book book = new Book();
private List<Book> books = new ArrayList<Book>();
private Book selectedUser;
public String reinit() {
book = new Book();
return null;
}
setters and getters are included here
}
Lets split this question in two parts.
First:
When you want to display updated values (e.g. with a h:outputText), you need to update this element. Updating this element means, it will fetch the current value of it's backing bean.
Do it like this:
<p:commandButton ... update="idToUpdate1, idToUpdate2, ..." >
In order to get the idToUpdate check Naming Container in JSF2/PrimeFaces.
If you have many components which need an update, I would recomment grouping them into one NamingContainer (e.g. p:outputPanel). So you only have to update the NamingContainer, and not every single component.
Second:
#CreateBookBean.selectUser.fname means: "Fetch the CreateBookBean, fetch it's property selectUser and fetch the property of selectUser called fname".
In this case you would have these class layouts:
public class CreateBookBean {
private Book selectedUser;
....
public Book getSelectedUser() {
return this.selectedUser;
}
}
public class Book {
private String fname;
....
public String getFname() {
this.fname;
}
}
#CreateBookBean.fname means: "Fetch the CreateBookBean, fetch it's property fname".
In this case you would have this class layout:
public class CreateBookBean {
private String fname;
....
public String getFname() {
return this.fname;
}
}
According to this code you posted, i guess that the CreateBookBean has a property called selectedUser (the code reveals it: target="#{CreateBookBean.selectedUser}"), and the selectUser has a property fname.
Use the Update attribute in the button your using to display the dialog box, for example, <p:commandButton update="dialogBoxId" . . ./> in order to display the items from your datatable.

JSF h:selectOneMenu is never set even when using f:ajax

I want to implement a filtering facility in a JSF web application as follows: The users can add as many filters as they want. They can also delete them. So I am having a dataTable of filters. Each row consists of one h:selectOneMenu which has an ajax “change” event in order to make a second h:selectOneMenu visible in the same row. The options of the second h:selectOneMenu are calculated dynamically according to the selected option of the first.
The problem is that the value of second h:selectOneMenu is never set to the back-end object even if I added an ajax event. However the value of the first h:selectOneMenu is set.
I have the following fragment of code in an .xhtml page:
<h:form id="filterForm">
<h:dataTable id="filterTable" value="#{filterManager.filters}" var="filter">
<h:column>
<h:outputLabel value="#{msgs.filterBy}:" for="availableFilters" />
<h:selectOneMenu id="availableFilters" value="#{filter.filter}">
<f:selectItems value="#{filterManager.getProperties(typeSelector.typeSelected)}" />
<f:ajax event="change" render=":filterForm" />
</h:selectOneMenu>
</h:column>
<h:column>
<h:panelGroup id="filterValuesPanel" >
<h:outputLabel value="#{msgs.value}:" for="filterValues" rendered="#{!filter.filterEmpty}" />
<h:selectOneMenu value="#{filter.value}" id="filterValues" rendered="#{!filter.filterEmpty}" >
<f:selectItems value="#{filterManager.getPossibleAnswers(filter)}" />
<f:ajax event="change" render=":filterForm" />
</h:selectOneMenu>
</h:panelGroup>
</h:column>
<h:column>
<h:commandButton value="#{msgs.delete}" title="#{msgs.deleteFilter}">
<f:ajax event="click" listener="#{filterManager.removeFilter(filter)}" render=":filterForm" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="#{msgs.addNewFilter}">
<f:ajax event="click" listener="#{filterManager.addNewFilter}" render=":filterForm" />
</h:commandButton>
</h:form>
I have a bean called “FilterManager” which has a ViewScoped. Important parts are shown below:
#ManagedBean
#ViewScoped
public class FilterManager implements Serializable {
private List<Filter> filters; // it has a getter
private int currentFilterId;
public void addNewFilter(AjaxBehaviorEvent event) {
this.currentFilterId++;
this.filters.add(Filter.getEmptyFilter(this.currentFilterId));
}
public void removeFilter(Filter filter) {
this.filters.remove(filter);
}
...
}
The Filter class is a normal class (not a bean) and is shown below:
public class Filter implements Serializable {
private int id;
private String filter;
private String value;
public String getFilter() {
return filter;
}
public void setFilter(String theFilter) {
if (theFilter != null && !theFilter.isEmpty())
this.filter = theFilter;
}
public String getValue() {
return value;
}
public void setValue(String theValue) {
this.value = theValue;
}
public boolean isFilterEmpty() {
return this.filter == null || this.filter.isEmpty();
}
...
}
Notice that TypeSelector is a SessionScoped bean which has a typeSelected property along with getter and setter.
The problem is: filter.filter is set correctly whereas filter.value is never set. I can't find the problem so I need your help please. Apologies for all this code but I needed to provide you with all the necessary details.
Thanks in advance!
Okay guys that was my fault. I had a bug in FilterManager.getPossibleAnswers(Filter filter) method. Basically, at the end of the method, I was setting filter.value to the first element of List unconditionally. Eg instead of writing
if (filter.getValue() == null || filter.getValue().isEmpty()) {
SelectItem first = answers.get(0);
filter.setValue((String) first.getValue());
}
I just wrote:
SelectItem first = answers.get(0);
filter.setValue((String) first.getValue());
Although filter.value was updating as normal, the value was changing back to default (first element in list) during re-rendering of dataTable component.

JSF datatable: adding and removing rows clear rows values

I have a h:datatable showing a list of rows, and the fields of each row are input fields.
I render an "Add Row" button before the table, and a "Remove Row" button on each row of the table.
The baking bean is viewScoped, and the buttons add/remove elements from the java list in the backing bean, and then return to the same view.
I set the immediate attribute to "true" in the buttons in order to not validate the input fields when I add or remove a row.
Everything works ok but one thing: the values of the input fileds are cleared. I thought that the view kept the values beacuse the bean is viewScoped.
How can I achieve adding/removing rows without triggering validations and keeping the values that were already typed by the user in the form?
My view:
<h:form>
<h:commandButton value="Añadir Fila" immediate="true" action="#{tablaController.addRowAction}" />
<h:dataTable value="#{tablaController.lista}" var="fila" cellpadding="0" cellspacing="0" border="1">
<f:facet name="header">TABLA</f:facet>
<h:column>
<f:facet name="header"><h:outputLabel value="NOMBRE" /></f:facet>
<h:inputText id="nom" value="#{fila.nombre}" />
<h:message for="nom" class="msjError" />
</h:column>
<h:column>
<f:facet name="header"></f:facet>
<h:commandButton value="Quitar Fila" immediate="true" action="#{tablaController.removeRowAction(fila)}" />
</h:column>
</h:dataTable>
</h:form>
My backing bean:
#ManagedBean(name="tablaController")
#ViewScoped
public class TablaController {
private List<Fila> lista;
...
public TablaController() { }
...
#PostConstruct
public void init() {
this.lista = new ArrayList<Fila>();
for (int i=0; i<5; i++) {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(i,fila);
}
}
...
public String addRowAction () {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(fila);
return "";
}
public String removeRowAction (Fila f) {
boolean exito = this.lista.remove(f);
return "";
}
...
}
UPDATE --> MY SOLUTION:
I write here my solution if someone is interested.
The problem is that I use immediate="true" to skip validations, but this makes to skip the update_model_values too, so that the values entered by the user in the form are lost after clicking the add/remove buttons and re-redenring the page.
As I use "JSR-303 bean validation", my solution was to skip validations using the f:validateBean to enable/disable them. Depending on the button I click, if I want the validations to execute, I enable the bean validation (for example in a "submit" button), and if I want to skip them, I disable bean validation (like in the add/remove row buttons). But anyway the update_model_values always executes, so the values are not lost.
Here's the view:
<h:form>
<f:validateBean disabled="#{!empty param['disableValidation']}">
<h:commandButton value="Añadir Fila" action="#{tablaController.addRowAction}">
<f:param name="disableValidation" value="true" />
</h:commandButton>
<h:dataTable value="#{tablaController.lista}" var="fila" cellpadding="0" cellspacing="0" border="1">
<f:facet name="header">TABLA</f:facet>
<h:column>
<f:facet name="header"><h:outputLabel value="NOMBRE" /></f:facet>
<h:inputText id="nom" value="#{fila.nombre}" />
<h:message for="nom" class="msjError" />
</h:column>
<h:column>
<f:facet name="header"></f:facet>
<h:commandButton value="Quitar Fila" action="#{tablaController.removeRowAction(fila)}">
<f:param name="disableValidation" value="true" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="Submit" action="#{tablaController.saveData}" />
</f:validateBean>
</h:form>
The backing bean:
#ManagedBean(name="tablaController")
#ViewScoped
public class TablaController {
private List<Fila> lista;
...
public TablaController() { }
...
#PostConstruct
public void init() {
this.lista = new ArrayList<Fila>();
for (int i=0; i<5; i++) {
Fila fila = new Fila();
fila.setNombre("fila "+i);
this.lista.add(i,fila);
}
}
...
public String addRowAction () {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(fila);
return "";
}
public String removeRowAction (Fila f) {
this.lista.remove(f);
return "";
}
...
public String saveData () {
...
//processes the valid data
//for example, calls to a service method to store them in a database
...
return "";
}
...
}
I set the immediate attribute to "true" in the buttons in order to not validate the input fields when I add or remove a row.
immediate="true" is the wrong tool for the job. It should be used to prioritize validation, not to enable/disable validation. The difference is rather huge as you encountered yourself.
You want to trigger validation conditionally. In case of e.g. required="true" that'd be as easy as
<h:inputText ... required="#{saveButtonPressed}" />
where #{saveButtonPressed} evaluates true when the save button is pressed. E.g. when its client ID is present in request parameter map.
In case of JSR 303 bean validation, that'd be a matter of
<f:validateBean disabled="#{not saveButtonPressed}">
<h:inputText ... />
</f:validateBean>
or with OmniFaces <o:validateBean> which allows controlling that on a per-command basis.
<h:commandButton id="add" ...>
<o:validateBean disabled="true" />
</h:commandButton>
I had exactly the same problem. In short, you can NOT use immediate for action that update data table(UIData) or facelet repeat. Short explanation:submitted values are not kept for re-display if inputs in UIData do not go through validation. Long explanation can be found here: long explanation and a related bug in Mojarra

h:inputText inside a4j:repeat

I have a List of strings in my object, and I was hoping to be able to edit them with an a4j:repeat.
Below is my code:
<a4j:repeat value="#{Controller.object.stringList}" var="item" >
<h:panelGrid columns="2">
<h:outputLabel value="ID:" />
<h:inputText value="#{item}" />
</h:panelGrid>
</a4j:repeat>
My problem is that the values of the items never get changed when I submit my form. I've had a look at the livedemo but even after adding the UpdateBean, it still didn't work.
Any ideas?
The objects in your repeat need to follow the bean standard if you want to write back to them. I'm guessing that they are just Strings in your example?
Try this:
public class StringBean {
private String value;
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
along with:
<h:inputText value=#{item.value} />

Resources