Select first row on load of lazy p:dataTable - jsf

Need some help selecting the PrimeFaces p:dataTable 1st row on page load, here's my code so far:
<p:dataTable id="dtbList" value="#{Controller.items}" var="item" widgetVar="dataTableList" lazy="true"
selection="#{Controller.selectedValue}" rowKey="#{item.key}"
scrollable="true" scrollHeight="133">
<p:ajax event="rowSelectRadio" listener="#{Controller.handleSelectList}" update="dtbList"
oncomplete="resetScroll();"/>
...
...
...
</p:dataTable>
I've tried using ajax event to no avail
<p:ajax event="page" onsuccess="PF('dataTableList').selectRow(0);"/>
Wondering where I did wrong.

If you know the rowKey (the id) of your first row try to add the property dynamic="true" in your dataTable component like this :
<p:dataTable id="dtbList"
value="#{Controller.items}" var="item"
widgetVar="dataTableList" lazy="true"
selection="#{Controller.selectedValue}"
rowKey="#{item.key}"
scrollable="true" scrollHeight="133"
dynamic="true">
...
...
...
</p:dataTable>
And, in your bean(Controller) create a method annotated by #PostConstruct, in witch you can select the best element.
Like this:
#PostConstruct
public void init() {
this.selectedValue = new SelectedValueEntityType();
this.selectedValue.setKey('yourKey');
}

The page event is triggered on pagination, so not on the initial load.
You might want to make the controller a property of the LazyDataModel you've implemented (assuming you did; if you are using the JpaLazyDataModel, extend it). Now you can access the controller from the load method. You can now simply check if no selection was made and set the first item that was fetched in the load method as the selected item of the controller.
See also: https://primefaces.github.io/primefaces/12_0_0/#/components/datatable

Related

Primefaces datatable update in f:facet name="header" not working

I want to update a button in the header facet of a primefaces datatable and it does not work. I copied the button outside the datatable everything works fine.
The update should happen when the filter event of the datatable gets fired. I explicitly update the datatable, the outside- and the inside-button.
The intention is to display a button with an icon when no filter is set and another icon when a filter is used. In this example I simplyfied the use case: when no filter is used there is a open-lock icon, if I type something in a filter a closed-lock icon should be displayed. To release the lock one has to click the button (I did not implement the deletion of the filter in the datatable).
From what I understand I use the correct ID of the button inside the header. So I do not know why this does not work?
I am using mojarra 2.2 and primefaces 6.
<h:form id="id_form">
<p:dataTable
id="id_table"
value="#{stateController.names}"
var="currentName">
<p:ajax
event="filter"
listener="#{stateController.markLocked()}"
update="id_table id_form:id_table:id_button_inside id_form:id_button_outside"/>
<p:column
filterBy="#{currentName}"
filterMatchMode="contains">
<f:facet name="header">
<p:commandButton
id="id_button_inside"
action="#{stateController.markUnlocked()}"
icon="#{stateController.locked ? 'ui-icon-locked' : 'ui-icon-unlocked'}"
update="id_form"/>
</f:facet>
<h:outputText value="#{currentName}" />
</p:column>
</p:dataTable>
<p:commandButton
id="id_button_outside"
action="#{stateController.markUnlocked()}"
icon="#{stateController.locked ? 'ui-icon-locked' : 'ui-icon-unlocked'}"
update="id_form"
/>
</h:form>
#Named(value = "stateController")
#SessionScoped
public class StateController implements Serializable
{
private boolean locked;
private List<String> names;
#PostConstruct
private void init()
{
locked = false;
names = new ArrayList<>();
names.add("peter");
}
public void markLocked()
{
locked = true;
}
public void markUnlocked()
{
locked = false;
}
// getter + setter omitted
}
I also tried to put a button in a separate column. With this button (which is displayed in every row of the datatable) everything works fine as well.
It's a bit late, but maybe someone will find it useful some day.
To solve Filou's problem, you need to define remoteCommand outside dataTable and make it update dataTable's header facet.
<p:remoteCommand name="rmtCommand" update="id_form:id_table:id_button_inside"/>
<p:dataTable
id="id_table"
value="#{stateController.names}"
var="currentName">
<p:ajax
event="filter"
listener="#{stateController.markLocked()}"
oncomplete="rmtCommand()"/>

Update primefaces datatable from actionListener [duplicate]

I am having difficulty re-rendering a PrimeFaces Datatable once a cell has been edited. Changing the value in one cell may change entries in the other cells, hence the need to refresh the entire table.
Here's the JSF page:
<h:form id="testForm">
<p:outputPanel id="testContainer">
<p:dataTable id="testTable" value="#{tableBean.data}" var="entry" editable="true" editMode="cell">
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />
<p:column headerText="Col1">
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{entry.col1}" /></f:facet>
<f:facet name="input"><p:inputText value="#{entry.col1}" /></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Col2">
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{entry.col2}" /></f:facet>
<f:facet name="input"><p:inputText value="#{entry.col2}" /></f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
<p:commandButton id="refreshButton" value="Redisplay" update="testContainer" />
</p:outputPanel>
</h:form>
And here's the backing bean:
#ManagedBean(name = "tableBean", eager = false)
#ViewScoped
public class TableBean {
public TableBean() {
RowData entry = new RowData("a1", "b1");
entries.add(entry);
entry = new RowData("a2", "b2");
entries.add(entry);
entry = new RowData("a3", "b3");
entries.add(entry);
}
public class RowData {
private String col1;
private String col2;
public RowData(String col1, String col2) {
this.col1 = col1;
this.col2 = col2;
}
public String getCol1() {
return col1;
}
public void setCol1(String col1) {
this.col1 = col1;
}
public String getCol2() {
return col2;
}
public void setCol2(String col2) {
this.col2 = col2;
}
}
private ArrayList<RowData> entries = new ArrayList<RowData>();
public List<RowData> getData() {
return entries;
}
public void onCellEdit(CellEditEvent event) {
entries.get(event.getRowIndex()).setCol1("Dummy Col 1");
entries.get(event.getRowIndex()).setCol2("Dummy Col 2");
}
}
When including update=":testForm:testContainer" within the cellEdit AJAX event, changing a cell value deletes the datatable on screen and only renders the cell content (along with the button) -- I do not understand why this is. When the update attribute is not specified, the table remains on screen with the active cell updated, but none of the other cells are updated (as to be expected).
The desired behaviour can be achieved (in a non-automated way) by not specifying the update attribute within the AJAX cellEdit event and clicking the Redisplay button after editing a cell's value. How can I achieve this in an automated way, and why does the update attribute not work as I expect?
I am using PrimeFaces 4.0.
The rowEdit and cellEdit events does by design inside the table not update/re-render anything else than the current row, even not when explicitly specified in update attribute. It's the consequence of PrimeFaces' a bit overzealous attempt to minimize the response size. This makes sense in most of the cases, but not in specifically your case. It's worth an issue report.
In the meanwhile, until they fix this behavior, your best bet is using <p:remoteCommand> to invoke the desired listener method and perform a full update of the table.
Rewrite
<p:dataTable ...>
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />
...
</p:dataTable>
to
<p:remoteCommand name="onCellEdit" action="#{tableBean.onCellEdit}" update="testContainer" />
<p:dataTable ...>
<p:ajax event="cellEdit" oncomplete="onCellEdit()" />
...
</p:dataTable>
The BaLusC solution has not worked directly for me. The onCellEdit needs a CellEditEvent as param. My workaround is as following:
<p:remoteCommand name="onCellEdit" update="testContainer" />
<p:dataTable ...>
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" oncomplete="onCellEdit()" />
...
</p:dataTable>
If none of the solutions worked for you, this worked for me
<p:dataTable ... id="theId" widgetVar="theWidget" ...>
<p:ajax event="rowEdit" listener="#{...}"
oncomplete="PF('theWidget').filter()"/>
....
I'm calling the filter method on the PF widget on ajax complete, any method that does a "reload" of the table should work, I used filter because my table had column filters.
I tested your code. First I moved p:commandButton out of p:outputPanel. Here is modified code:
<h:form id="testForm">
<p:outputPanel id="testContainer">
<p:dataTable id="testTable" value="#{tableBean.data}" var="entry" editable="true" editMode="cell">
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />
(...)
</p:dataTable>
</p:outputPanel>
<p:commandButton id="refreshButton" value="Redisplay" update="testContainer" />
</h:form>
I think this code doesn't work correctly. if you change anything in table, the p:ajax every time render full table. So, the program load basic data from TableBean constructor and deleted new data.
If I omit your p:ajax code there is not disapears any new data from screen. The refreshButton p:commandButton work correctly.
When including update=":testForm:testContainer" within the cellEdit
AJAX event, changing a cell value deletes the datatable on screen and
only renders the cell content (along with the button) -- I do not
understand why this is.
I think it is bad design add update=":testForm:testContainer" to ajax, because it's update your outputPanel more than as exepted (first time work correctly, second time couldn't edit cell, because the program update to many times table).
I don't know what is your goal. If you want render table without a commandButton, then could you specify one javascript event or p:message and this disappear you can render table.
I think if you omit update in p:ajax or specify update of one p:message, and move p.commandButton out of testContainer your code start work correctly.
After 5 years, this problem still exists. Unfortunately, while Baukes solution is extremly helpful and includes important insights it's still incomplete, as ltlBeBoy already pointed out in his comment. Subsequent edits without change lead to an inconsistent table state, where no more edits are possible. The reason is, that the oncomplete remote update comes after the edit mode of the new cell is already activated. So the edit mode of the new cell is destroyed by the update. However, the update can't be done in Ajax listener tableBean#onCellEdit, as this would display the table erroneously with one cell only.
The solution is, to execute the update in the remote commands listener and only, if a change happend. So, in tableBean you implement a programmatic update, a remote listener and a flag that indicates change:
public static void update(String id) {
PrimeFaces pf = PrimeFaces.current(); //RequestContext.getCurrentInstance() for <PF 6.2
if(pf.isAjaxRequest()) pf.ajax().update(id);
}
/** Whether onCellEdit changed the value */
boolean onCellEditChange;
public void onCellEditRemote() {
if(!onCellEditChange) update("testContainer");
}
public void onCellEdit(CellEditEvent event) {
... onCellEditChange= /*Change happend*/ ...
}
The remote command has no update attribute any more:
<p:remoteCommand name="onCellEdit" actionListener="#{tabelBean.onCellEditRemote}"/>
try using process
<p:remoteCommand name="onCellEdit" update="testContainer" process="#this" />
<p:dataTable ...>
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" oncomplete="onCellEdit()" process="#this" />
...
</p:dataTable>
This is my first post ever in here. As ltlBeBoy mentioned, BalusC's solution works only if the cell editing is done with an enter key hit.
None of the other suggestions listed in here worked for me.
In my case, I just wanted to update a specific row (that has each column's average) in the table on cellEdit event. I'm posting this in case if someone out there is looking for a solution: I managed to achieve this by separating that row in a second datatable right below the main one. Here's the code:
<pf:ajax event="cellEdit"
listener="#{newAgentMetricBacking.onCellEdit}"
update="c21413" />
<pf:dataTable id="c21413"
styleClass="noHeader"
value="">
<pf:column>
<h:outputText value="#{bundle.TeamAverage}"/>
</pf:column>
<pf:columns columnIndexVar="j"
value="#{newAgentMetricBacking.averageArray}"
var="avg">
<h:outputText value="#{newAgentMetricBacking.
averageArray[j]}"/>
</pf:columns>
</pf:dataTable>
Otherwise, as of today, I couldn't find a better solution for updating either the whole table or a specific row specifically upon success of cellEdit event.
Cheers!

Primefaces' commandLink works only on the first page of a dataTable

I have a column with p:commandLink inside p:dataTable, which has a paginator. When user clicks on a commandLink, a dialog opens, displaying data of that row.
datatable html code:
<p:dataTable id="dtSample" value="#{sessionBean.sampleList}"
binding="#{requestBean.dtSampleList}"
paginator="true" paginatorPosition="bottom"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="#{10,25,50}"
currentPageReportTemplate="({startRecord} of {totalRecords})"
var="item" emptyMessage="No entries." rows="10" rowKey="#{item.id}">
<p:column headerText="Id">
<p:commandLink id="lnkSample"
action="#{requestBean.onLinkClick(item)}"
oncomplete="PF('dlgSample').show();"
update="#(.dialogClass)">
<h:outputText value="#{item.id}" />
</p:commandLink>
</p:column>
<p:column headerText="Code">
<h:outputText value="#{item.code}" />
</p:column>
<p:column headerText="Description">
<h:outputText value="#{item.descr}" />
</p:column>
</p:dataTable>
Request bean:
public class RequestBean {
private SessionBean sessionBean;
private DataTable dtSampleList;
public void init() {
// load samle list
loadSampleList();
}
public String onLinkClick(Sample sample) {
getSessionBean().setSelectedSample(sample);
return "success";
}
private void loadSampleList() {
List<Sample> list = new ArrayList<Sample>();
for (int i = 0; i < 100; i++) {
Sample tmp = new Sample();
tmp.setId(new BigDecimal(i + 1));
tmp.setCode("code" + (i + 1));
tmp.setDescr("desc" + (i + 1));
list.add(tmp);
}
getSessionBean().setSampleList(list);
}
// getters and setters
}
Session bean:
public class SessionBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<Sample> sampleList;
private Sample selectedSample;
// getters and setters
}
dialog html code:
<p:dialog id="dlgSample" closeOnEscape="true" widgetVar="dlgSample"
styleClass="dialogClass" modal="true">
<p:panelGrid columns="1">
<h:outputText value="Id: #{sessionBean.selectedSample.id}" />
<h:outputText value="Code: #{sessionBean.selectedSample.code}" />
<h:outputText value="Description: #{sessionBean.selectedSample.descr}" />
</p:panelGrid>
</p:dialog>
When I click on a link on the first page of a datatable, link action is executed and a dialog, displaying row data, is properly refreshed. But when I move to any of the following pages of a datatable, clicking a link doesn't refresh the data in a dialog (the link action is not called, so the data in a dialog is wrong - selectedSample variable has old value). Of course when I go back to the first page of the datatable, command link works again (action method is called and data is refreshed).
What am I doing wrong? Why is action method not called on any datatable page?
I'm using Primefaces 5.2.
Looks like the problem was in a PF dataTable component. There were first and rows attributes missing and after adding them, commandLinks on all pages work as expected.
What am I doing wrong? Why is action method not called on any datatable page?
A common misstake leading to that behaviour is that your state is not consistent: To process the form submit, JSF will recreate the exact same view as in the prior request, and then apply the changes (execute the action)
If this new view is now different than the view before the submit was, every action is aborted and not invoked. (Different in terms of involved elements. I.e. if your commandLink was rendered="true" before submitting, it needs to be rendered="true" during the APPLY_REQUEST_VALUES-Phase).
So, from your description I would assume, that your table is falling back to page 1, which will remove any link on page 2 from the view and abort it's view action, because the element is no longer rendered.
For the same reason, links on page 1 are working, because even if your table looses track of the current page - it will render page 1, so you have the same view as before, so the submission works.
You could easily verify this, by increasing the number of elements per page and see that every link moved from page 2 to page 1 is now working.
But without seeing the whole bean I can only assume this. For easy testing, set your bean to #SessionScoped and see if this resolves it.
For more ideas, see this post: commandButton/commandLink/ajax action/listener method not invoked or input value not updated
When putting components such as p:commandLink in a p:dataTable row, you should always specify
process="#this"
So, in your case, I would try :
<p:commandLink id="lnkSample"
action="#{bean.onLinkClick(item)}"
oncomplete="PF('dlgSample').show();"
update="#(.dialogClass)">
<h:outputText value="#{item.id}" />
</p:commandLink>
Doing so, you are sure that only the click on the link will be processed, and no other submission will be performed.

Updating entire <p:dataTable> on complete of <p:ajax event="cellEdit">

I am having difficulty re-rendering a PrimeFaces Datatable once a cell has been edited. Changing the value in one cell may change entries in the other cells, hence the need to refresh the entire table.
Here's the JSF page:
<h:form id="testForm">
<p:outputPanel id="testContainer">
<p:dataTable id="testTable" value="#{tableBean.data}" var="entry" editable="true" editMode="cell">
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />
<p:column headerText="Col1">
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{entry.col1}" /></f:facet>
<f:facet name="input"><p:inputText value="#{entry.col1}" /></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Col2">
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{entry.col2}" /></f:facet>
<f:facet name="input"><p:inputText value="#{entry.col2}" /></f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
<p:commandButton id="refreshButton" value="Redisplay" update="testContainer" />
</p:outputPanel>
</h:form>
And here's the backing bean:
#ManagedBean(name = "tableBean", eager = false)
#ViewScoped
public class TableBean {
public TableBean() {
RowData entry = new RowData("a1", "b1");
entries.add(entry);
entry = new RowData("a2", "b2");
entries.add(entry);
entry = new RowData("a3", "b3");
entries.add(entry);
}
public class RowData {
private String col1;
private String col2;
public RowData(String col1, String col2) {
this.col1 = col1;
this.col2 = col2;
}
public String getCol1() {
return col1;
}
public void setCol1(String col1) {
this.col1 = col1;
}
public String getCol2() {
return col2;
}
public void setCol2(String col2) {
this.col2 = col2;
}
}
private ArrayList<RowData> entries = new ArrayList<RowData>();
public List<RowData> getData() {
return entries;
}
public void onCellEdit(CellEditEvent event) {
entries.get(event.getRowIndex()).setCol1("Dummy Col 1");
entries.get(event.getRowIndex()).setCol2("Dummy Col 2");
}
}
When including update=":testForm:testContainer" within the cellEdit AJAX event, changing a cell value deletes the datatable on screen and only renders the cell content (along with the button) -- I do not understand why this is. When the update attribute is not specified, the table remains on screen with the active cell updated, but none of the other cells are updated (as to be expected).
The desired behaviour can be achieved (in a non-automated way) by not specifying the update attribute within the AJAX cellEdit event and clicking the Redisplay button after editing a cell's value. How can I achieve this in an automated way, and why does the update attribute not work as I expect?
I am using PrimeFaces 4.0.
The rowEdit and cellEdit events does by design inside the table not update/re-render anything else than the current row, even not when explicitly specified in update attribute. It's the consequence of PrimeFaces' a bit overzealous attempt to minimize the response size. This makes sense in most of the cases, but not in specifically your case. It's worth an issue report.
In the meanwhile, until they fix this behavior, your best bet is using <p:remoteCommand> to invoke the desired listener method and perform a full update of the table.
Rewrite
<p:dataTable ...>
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />
...
</p:dataTable>
to
<p:remoteCommand name="onCellEdit" action="#{tableBean.onCellEdit}" update="testContainer" />
<p:dataTable ...>
<p:ajax event="cellEdit" oncomplete="onCellEdit()" />
...
</p:dataTable>
The BaLusC solution has not worked directly for me. The onCellEdit needs a CellEditEvent as param. My workaround is as following:
<p:remoteCommand name="onCellEdit" update="testContainer" />
<p:dataTable ...>
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" oncomplete="onCellEdit()" />
...
</p:dataTable>
If none of the solutions worked for you, this worked for me
<p:dataTable ... id="theId" widgetVar="theWidget" ...>
<p:ajax event="rowEdit" listener="#{...}"
oncomplete="PF('theWidget').filter()"/>
....
I'm calling the filter method on the PF widget on ajax complete, any method that does a "reload" of the table should work, I used filter because my table had column filters.
I tested your code. First I moved p:commandButton out of p:outputPanel. Here is modified code:
<h:form id="testForm">
<p:outputPanel id="testContainer">
<p:dataTable id="testTable" value="#{tableBean.data}" var="entry" editable="true" editMode="cell">
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />
(...)
</p:dataTable>
</p:outputPanel>
<p:commandButton id="refreshButton" value="Redisplay" update="testContainer" />
</h:form>
I think this code doesn't work correctly. if you change anything in table, the p:ajax every time render full table. So, the program load basic data from TableBean constructor and deleted new data.
If I omit your p:ajax code there is not disapears any new data from screen. The refreshButton p:commandButton work correctly.
When including update=":testForm:testContainer" within the cellEdit
AJAX event, changing a cell value deletes the datatable on screen and
only renders the cell content (along with the button) -- I do not
understand why this is.
I think it is bad design add update=":testForm:testContainer" to ajax, because it's update your outputPanel more than as exepted (first time work correctly, second time couldn't edit cell, because the program update to many times table).
I don't know what is your goal. If you want render table without a commandButton, then could you specify one javascript event or p:message and this disappear you can render table.
I think if you omit update in p:ajax or specify update of one p:message, and move p.commandButton out of testContainer your code start work correctly.
After 5 years, this problem still exists. Unfortunately, while Baukes solution is extremly helpful and includes important insights it's still incomplete, as ltlBeBoy already pointed out in his comment. Subsequent edits without change lead to an inconsistent table state, where no more edits are possible. The reason is, that the oncomplete remote update comes after the edit mode of the new cell is already activated. So the edit mode of the new cell is destroyed by the update. However, the update can't be done in Ajax listener tableBean#onCellEdit, as this would display the table erroneously with one cell only.
The solution is, to execute the update in the remote commands listener and only, if a change happend. So, in tableBean you implement a programmatic update, a remote listener and a flag that indicates change:
public static void update(String id) {
PrimeFaces pf = PrimeFaces.current(); //RequestContext.getCurrentInstance() for <PF 6.2
if(pf.isAjaxRequest()) pf.ajax().update(id);
}
/** Whether onCellEdit changed the value */
boolean onCellEditChange;
public void onCellEditRemote() {
if(!onCellEditChange) update("testContainer");
}
public void onCellEdit(CellEditEvent event) {
... onCellEditChange= /*Change happend*/ ...
}
The remote command has no update attribute any more:
<p:remoteCommand name="onCellEdit" actionListener="#{tabelBean.onCellEditRemote}"/>
try using process
<p:remoteCommand name="onCellEdit" update="testContainer" process="#this" />
<p:dataTable ...>
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" oncomplete="onCellEdit()" process="#this" />
...
</p:dataTable>
This is my first post ever in here. As ltlBeBoy mentioned, BalusC's solution works only if the cell editing is done with an enter key hit.
None of the other suggestions listed in here worked for me.
In my case, I just wanted to update a specific row (that has each column's average) in the table on cellEdit event. I'm posting this in case if someone out there is looking for a solution: I managed to achieve this by separating that row in a second datatable right below the main one. Here's the code:
<pf:ajax event="cellEdit"
listener="#{newAgentMetricBacking.onCellEdit}"
update="c21413" />
<pf:dataTable id="c21413"
styleClass="noHeader"
value="">
<pf:column>
<h:outputText value="#{bundle.TeamAverage}"/>
</pf:column>
<pf:columns columnIndexVar="j"
value="#{newAgentMetricBacking.averageArray}"
var="avg">
<h:outputText value="#{newAgentMetricBacking.
averageArray[j]}"/>
</pf:columns>
</pf:dataTable>
Otherwise, as of today, I couldn't find a better solution for updating either the whole table or a specific row specifically upon success of cellEdit event.
Cheers!

Add a new row to a p:datatable then submit content

I'm trying to add a new row in a Primefaces datatable, then I would like to submit the content of this table and do some business logic. The datatable model is a collection that is maintained in a ViewScoped managed bean.
I'm using JSF 2.1 with Primefaces 3.3.
Short example:
<h:form id="my-form">
<p:dataTable value="#{testBean.list}" var="s" id="datatable">
<p:column>
<h:inputText value="#{s}"/>
</p:column>
<f:facet name="footer">
<p:commandButton value="Add row" action="#{testBean.addRow()}" process="#form" update="#form" immediate="true" />
<p:commandButton value="Do stuff" action="#{testBean.doSomeLogic()}" process="#form" update="#form"/>
</f:facet>
</p:dataTable>
</h:form>
Managed Bean:
#ManagedBean
#ViewScoped
public class TestBean implements Serializable {
private List<String> list;
public TestBean() {
}
#PostConstruct
public void init() {
list = new ArrayList<String>();
list.add("one");
list.add("two");
}
public void addRow(){
list.add(new String());
}
public void doSomeLogic(){
for (String string : list) {
System.out.println(string);
}
}
// getters and setters
}
What actually happens:
the user clicks on "add row" button, a new row is added (I need immediate to be true so no validation is done, those fields are part of a bigger form).
the user clicks on "do stuff", the collection has the right size (with new rows) but the user's input in not taken into account (neither modification to pre exiting rows, nor new values in freshly added rows).
What can I do to submit the new values too? I'm only beginning JSF and I'm not sure I'm already 100% getting it.
Thanks for your help.
Possible duplicates:
Add a row to h:dataTable via AJAX with request-scoped bean without losing the row data
How to Dynamically add a row in a table in JSF?
JSF datatable: adding and removing rows clear rows values
Edit: problem is solved thanks to Jitesh, a working example can be found here: JSF2, can I add JSF components dynamically?
The only problem is you are using immutable object in inputText. To understatnd this check out BaluC's Answer
According to it "As being an immutable object, the String doesn't have a setter method. The will never be able to set the entered value."
Try to remove immediate attribute from the commandButton you will find that on insertion of each row the data will be cleared.
If I understand correctly, there are some validations elsewhere in the form that are failing. When any of the submitted form values fail validation then none of the submitted values are applied to the managed bean unless immediate is used. This is why it seems that you are able to add a new row but not with the doStuff method. You did not add immediate to doStuff.
But stating that there are a few things you could do much more cleanly and efficiently.
First, the action attribute should really be used for navigation actions. JSF expects that methods bound to an action have a return value that represents the navigation result. For void methods it is better to use actionListener. For more information on the difference between action and actionListener read here: Differences between action and actionListener
Secondly, why not just set process and update to only the data table component and then you don't have to worry about other form validations? Here is an example:
<h:form id="my-form">
<p:dataTable value="#{testBean.list}" var="s" id="datatable">
<p:column>
<h:inputText value="#{s}"/>
</p:column>
<f:facet name="footer">
<p:commandButton value="Add row" actionListener="#{testBean.addRow}"
process=":my-form:datatable" update=":my-form:datatable" />
<p:commandButton value="Do stuff" actionListener="#{testBean.doSomeLogic}"
process=":my-form:datatable" update=":my-form:datatable" />
</f:facet>
</p:dataTable>
</h:form>

Resources