I have a table with a date column that always null. The data is a LazyDataModel child. Also i have row editing.
<p:dataTable id="dataTable" var="Var" value="#{tableBean.model}"
lazy="true"...........
<p:ajax event="rowEdit" listener="#{tableBean.onRowEdit}"
update=":dataTableForm:messages"/>
<p:column sortBy="VarName">
<f:facet name="header">
<h:outputText value="#{msg['Var.table.header.assignee']}"/>
</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{Var.Name}"/>
</f:facet>
<f:facet name="input">
<h:inputText id="assigneeNameInput" styleClass="row-input" value="#{Var.Name}"/>
<p:message for="assigneeNameInput"/>
</f:facet>
</p:cellEditor>
</p:column>
<f:facet name="header">
<h:outputText value="#{msg['var.table.header.action']}"/>
</f:facet>
<p:rowEditor/>
</p:column>
I need to delete edited row if date column was filled.
I try this
public void onRowEdit(RowEditEvent event) {
Var updatedVar = (Var) event.getObject();
if (updatedVar.getReturnDate() != null) {
updatedVar = null;
}
}
And this
public void onRowEdit(RowEditEvent event) {
Var updatedVar = (Var) event.getObject();
if (updatedVar.getReturnDate() != null) {
((List<T>) getWrappedData()).remove(oldEntry);
}
}
Both attempts did not work, only if update table twice via remoteCommand . Suggest the decision. Thanks!
Edit: Data removed from lazydatamodel, but on page i still had updated row.
Edit : JSF application lifecycle consist of six phases.
Phase 4:Update model values :
After the JSF checks that the data is valid, it walks over the component tree and set the corresponding server-side object properties to the components' local values. The JSF will update the bean properties corresponding to input component's value attribute.
Phase 5: Invoke application :
During this phase, the JSF handles any application-level events, such as submitting a form / linking to another page.
So, invocation onRowEdit() method occur after dataTable's update.
Related
To better read the contents of a cell within a dataTable, I used a commandLink to bring up a dialog box.
This works fine as long as the sortOrder of the dataTable is set to ascending. Upon using sortOrder desc and clicking the commandLink, the dialog brings up the result of the item that would have been there, had the sortOrder been ascending (in other words, in a desc dataTable -8,7,....,2,1- with 8 rows, clicking on row with id =2 will bring up the contents of row id=7).
What causes this mix-up in IDs? Am I not storing the actual clicked on item in the backing bean temporarily, which should not be affected by the sortOrder? IS there a better practice for what I am trying to accomplish?
PF version 5.3, JSF 2.2.7
dataTable and dialog
<p:dataTable id="improvementTable" var="improvement" widgetVar="improvementsTable" value="#{Controller.improvements}" sortBy="#{improvement.id}" sortOrder="descending">
<p:column headerText="ID">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{improvement.id}" />
</f:facet>
<f:facet name="input">
<p:inputText id="modelInput" value="#{improvement.id}" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column>
<p:commandLink id="detailOut" value="#{improvement.detail}" action="#{Controller.setSelectedImprovement(improvement)}" process="#this" oncomplete="PF('wDetail').show();" update=":dlgDetail" />
</p:column>
</p:dataTable>
</h:form>
<p:dialog id="dlgDetail" widgetVar="wDetail">
<h:outputText value="#{Controller.selectedImprovement.detail}" />
</p:dialog>
In the Bean
#ManagedBean (name="Controller")
#RequestScoped
public class Controller{
private List<Improvement> improvements;
private Improvement selectedImprovement;
#PostConstruct
public void load() {
CIMImprovementDao cimDao = new CIMImprovementDao();
improvements = cimDao.getAll();
}
public List<Improvement> getImprovements() {
return improvements;
}
public Improvement getSelectedImprovement() {
return selectedImprovement;
}
public void setSelectedImprovement(Improvement selectedImprovement) {
this.selectedImprovement = selectedImprovement;
}
}
I'm using cell editor in Primefaces to update cells in a datatable. However I want to validate the input before I confirm the change.
I have used FacesContext.getCurrentInstance().validationFailed(); for this purpose but still getting the cell updated.
This is how I'm implementing it:
<p:dataTable value="#{bean.list}" var="var" id="table" editMode="cell" editable="true">
<p:ajax event="cellEdit" listener="#{bean.onCellEdit}" update="#form"/>
<p:column headerText="Quantity">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{var.quantity}"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{var.quantity}"/>
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
Bean Method:
public void onCellEdit(CellEditEvent event) {
//validate new value
if(!validate(event.getNewValue())){
//if validation returned false stop updating the cell
FacesContext.getCurrentInstance().validationFailed();
}
}
I want to stop updating the cell if the new value did not pass the validation, but the cell gets updated anyways. How can I solve this problem?
PS: Primefaces 3.5
What you're observing happens because because the celleditor's event happens in the INVOKE_APPLICATION phase, too late for any validation failure to have any effect.
You can just use the plain validator attribute on the <p:inputText/> like you would any other JSF input component. The behaviour will be the same, regardless of the fact that it's a facet of the <p:cellEditor/>
I have a datatable with primefaces, loaded about three records, it happens that I have in a column one inputText, it happens that the button is outside the datable record, and click the button I want to record, capture me inputText values, and to update records each dataTable.
<p:dataTable id="dataTable" var="confParamGen" value="#{regRolMB.paramLdap}"
rowIndexVar="rowIndex">
<p:column>
<f:facet name="header" >
<h:outputText value="N°" />
</f:facet>
<h:outputText value="#{rowIndex+1}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Number Long" />
</f:facet>
<h:outputText value="#{confParamGen.numberCort}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Value Role" />
</f:facet>
<p:inputText value="#{confParamGen.valuesRole}" style="width: 200px;" />
</p:column>
</p:dataTable>
<p:commandButton value="Save" rendered="#{regRolMB.showButtonUpdate}"
actionListener="#{regRolMB.actualizarRol}" styleClass="positionButton">
<f:attribute name="confParamGen" value="#{confParamGen}" />
</p:commandButton>
In the controller I have it so, but it falls to cast the Arraylist.
public void updateRol(ActionEvent event) {
List<DateGeneral> rolConPar = new ArrayList<DateGeneral>();
rolConPar = ((ArrayList<DateGeneral>) event.getComponent().getAttributes().get("confParamGen"));
for(DateGeneral dato: rolConPar){
System.out.println("===> "+dato.getValuesRole());
}
}
I get this error, although the problem is not the modified data capture of inputText, only captures the data loaded from DataTable
java.lang.ClassCastException: com.bbva.sca.adm.bean.DatoGeneral cannot be cast to java.util.ArrayList
The ClassCastException is being thrown because you've actually set an instance of DatoGeneral as attribute here:
<f:attribute name="confParamGen" value="#{confParamGen}" />
This is clearly not a List<DatoGeneral> (or List<DateGeneral> or whatever typo you made during careless oversimplifying/translating of the code; just use English all the time in code). Technically, you can solve it by passing the list itself instead:
<f:attribute name="confParamGen" value="#{regRolMB.paramLdap}" />
After all, this approach isn't making any sense. Your sole purpose seems to be just collecting the submitted values. In that case, you seem to be completely new to JSF and not yet fully understand why you're using JSF and what it is all capable of. JSF has already updated the model values with the submitted values. You just have to access the very same list behind <p:dataTable value> directly.
public void actualizarRol(ActionEvent event) {
for(DateGeneral dato: paramLdap){
System.out.println("===> "+dato.getValuesRole());
}
}
This way you can just get rid of the whole <f:attribute>.
My datatable load it like this:
public ArrayList<DatoGeneral> getParamLdap() {
try{
if(codSistema != null){
confParamGen = new ArrayList<DatoGeneral>();
confParamGen = datoGeneralService.obtenerParamGen(sistema.getConfLdap().getCdCodigo());
}
}catch(Exception e){
e.printStackTrace();
}
return (ArrayList<DatoGeneral>) confParamGen;
}
I have a data table with on-cell editing feature, and I want to update the data table to show the modified record by apply them a different style class.
Here are my problems:
If i do not update the data table when the onCellEdit event fires, records are correctly updated, but I cannot see the applyed style class for modified rows.
If I update the data table when the onCellEdit event fires and use the return key to update a value, all works fine, and I can see the applied style class for modified rows.
If I update the data table when the on-cell edit event fires and use the mouse clic to update a value (clicking on another row or on another cell within the same row), only the first value is updated correctly; when trying to update other values, the onCellEdit event triggers before I can insert the new value, so the event triggers with newValue=oldValue, for all the subsequent changes.
The xhtml page:
<h:form id="frm_tbl_riv">
<p:dataTable id="tbl_rilevazioni" var="rilevazione"
value="#{rilevazioni.rilevazioni}" widgetVar="tbl_rilevazioni_id"
editable="true" editMode="cell" scrollable="true" scrollHeight="350"
rowKey="#{rilevazione.idRilevazione}" selectionMode="single"
selection="#{rilevazioni.selezionata}">
<p:ajax event="rowSelect"
update=":tView:frm_tbl_riv:popup_rilevazioni" />
<p:ajax event="cellEdit" listener="#{rilevazioni.onCellEdit}"
update=":tView:frm_btn_riv" />
<!-- update=":frm_btn_riv :frm_tbl_riv" -->
<p:ajax event="contextMenu"
listener="#{rilevazioni.onRilevazioneSelezionata}"
update="#this" />
<p:column headerText="#{msg['rilevazione']}" width="130">
<f:facet name="header">
<h:outputText value="#{msg['rilevazione']}" />
</f:facet>
<h:outputText value="#{rilevazione.descRilevazione}" id="descRil" />
</p:column>
<p:column headerText="#{msg['valore']}"
styleClass="#{rilevazioni.isModificata(rilevazione) ? 'modificata' : ''}"
width="30">
<h:outputText value="#{rilevazione.valore}"
rendered="#{!rilevazioni.isModificabile(rilevazione)}" />
<p:cellEditor
rendered="#{rilevazioni.isModificabile(rilevazione)}">
<f:facet name="output">
<h:outputText value="#{rilevazione.valore}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{rilevazione.valore}"
label="#{msg['valore']}">
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
</h:form>
And the managed bean (view scoped):
#ManagedBean(name = "rilevazioni")
#ViewScoped
public class GestioneRilevazioniBean implements Serializable
{
// ...
public void onCellEdit(CellEditEvent event)
{
FacesContext context = FacesContext.getCurrentInstance();
FacesMessage msg = null;
Object nuovoValore = event.getNewValue();
Object vecchioValore = event.getOldValue();
int i = event.getRowIndex();
RilevazioneGiornaliera r = rilevazioni.get(i);
r.setIdUtente(userBean.getUserId());
if (!nuovoValore.equals(vecchioValore))
{
try
{
RilevazioniService.getInstance().updateRilevazioneGiornaliera(r);
modificate.add(r);
} catch (Throwable ex)
{
// ...
}
}
}
public boolean isModificata(RilevazioneGiornaliera riv)
{
return modificate.contains(riv);
}
public boolean isModificabile(RilevazioneGiornaliera rilevazione)
{
// some logic
return true;
}
}
If I use:
update=":frm_btn_riv :frm_tbl_riv"
for the on-cell edit event, I obtain the behaviour specified on point 2 and 3. The same with #form or #parent.
I have founded a solution to update the style class to the modified cell after the onCellEdit event fires.
Data table:
<p:ajax event="cellEdit" listener="#{rilevazioni.onCellEdit}"
oncomplete="handleRilevazioniCellEdit(xhr, status, args);" />
// ...
// within the cell editor
<p:inputText id="rilevazioniCellEditInputtext" value="#{rilevazione.valore}"
label="#{msg['valore']}" />
Javascript:
<script>
function handleRilevazioniCellEdit(xhr, status, args)
{
var modelInput = $('#parentId:' + args.rowIndex + '\\:rilevazioniCellEditInputtext');
var cell = modelInput.parent().parent().parent();
cell.addClass('modificata');
}
</script>
Managed bean, at the end of the onCellEdit() event:
RequestContext requestContext = RequestContext.getCurrentInstance();
requestContext.addCallbackParam("rowIndex", event.getRowIndex());
I need one help from you. I am using JSF 2.0 and I have a datatable component . One of the column in the datatable is an action column and I need to create a toolbar which contains different type of actionsource component such as command button, link etc. The type of actionsource is determined at run time and number of actionsource is also done at run time. How I can implement this in JSF 2.0
<p:dataTable value="#{listBranchBean1.rowDataModel}" var="rowItem"
id="myId" paginator="true"
paginatorTemplate="{FirstPageLink}{PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}{RowsPerPageDropdown} "
rowsPerPageTemplate="10,5,2" previousPageLinkLabel="<"
nextPageLinkLabel=">" widgetVar="branchTable"
selection="#{listBranchBean1.selectedBranchesPrime}"
resizableColumns="true"
sortBy="#{rowItem.columnsValueMap['branchId'].value}">
<f:facet name="header">
<p:outputPanel>
<h:outputText value="Search all fields:" />
<p:inputText id="globalFilter" onkeyup="branchTable.filter()"
style="width:150px" />
</p:outputPanel>
</f:facet>
<p:column selectionMode="multiple" style="text-align:left">
<f:facet name="header">
<h:outputText value="Select" />
</f:facet>
<h:outputText value="#{rowItem.uniqueId}" />
</p:column>
<p:column
rendered="#{listBranchBean1.columnsMap['objectId'].hidden==false}"
sortBy="#{rowItem.columnsValueMap['objectId'].value}"
filterBy="#{rowItem.columnsValueMap['objectId'].value}">
<f:facet name="header">
<h:outputText
value="#{listBranchBean1.columnsMap['objectId'].displayLabel}" />
</f:facet>
<h:outputText
value="#{rowItem.columnsValueMap['objectId'].value}" />
</p:column>
<p:column
rendered="#{listBranchBean1.columnsMap['actions'].hidden==false}">
<f:facet name="header">
<h:outputText
value="#{listBranchBean1.columnsMap['actions'].displayLabel}" />
</f:facet>
<p:toolbar>
<p:toolbarGroup>
<ui:repeat var="action"
value="#{rowItem.columnsValueMap['actions'].value}">
<p:commandButton title="#{action}" type="button">
</p:commandButton>
</ui:repeat>
</p:toolbarGroup>
</p:toolbar>
</p:column>
</p:dataTable>
I want to replace the last column with something like
<p:toolbar binding="#{listBranchBean1.getActions(rowItem)}">
</p:toolbar>
I appreciate your help
Prajeesh Nair
There is a difference between build-time and render-time in JSF. Build-time tags like <ui:repeat> have the ability to create new components dynamically, but they can only use data that is available at build-time.
However, using Java you are also allowed to alter the component tree programmatically, but this too can not just happen at any moment. The safe moment to do this is the preRenderViewEvent, which is a good bit later than the build-time moment (which is the restore view phase) and you should have all the data you need by then.
Inside an event handler for this event you can reference the tool bar you bound to your backing bean, and programmatically add columns to it.
For examples see:
http://balusc.omnifaces.org/2006/06/using-datatables.html#PopulateDynamicDatatable
http://arjan-tijms.omnifaces.org/2011/09/authoring-jsf-pages-in-pure-java.html
Do note that if your backing bean is #ViewScoped, you'd better not use binding but use a manual lookup instead. This is due to some bugs with respect to the view scope and binding components in JSF.
below code will create dynamic column on the basis of selected country
public void loadDynamicList() throws Exception {
int i=0;
dynamicList = new ArrayList<List<String>>();
dynamicList.add(Arrays.asList(new String[] { "ID1" }));
existingCountryList = new ArrayList<Country>();
String countryCode="US";
existingCountryList.add(getCountryService().getCountryByCode(countryCode));
Country country=getCountryService().getCountryByCode(countryCode);
countryLanguageSet=country.getCountryLanguage();
i=country.getCountryLanguage().size();
dynamicHeaders = new String[i] ;
int j=0;
for (CountryLanguage count: countryLanguageSet) {
System.out.println(count.getLanguage().getLanguageName());
dynamicHeaders[j]=count.getLanguage().getLanguageName();
j++;
}
}
public void populateDynamicDataTable() {
debugLogger.debug("populateDynamicDataTable:Enter");
// Create <h:dataTable value="#{myBean.dynamicList}" var="dynamicItem">.
HtmlDataTable dynamicDataTable = new HtmlDataTable();
dynamicDataTable.setValueExpression("value", createValueExpression("#{relationBean.dynamicList}", List.class));
dynamicDataTable.setVar("dynamicItem");
// Iterate over columns.
for (int i = 0; i < dynamicHeaders.length; i++) {
// Create <h:column>.
HtmlColumn column = new HtmlColumn();
dynamicDataTable.getChildren().add(column);
// Create <h:outputText value="dynamicHeaders[i]"> for <f:facet name="header"> of column.
HtmlOutputText header = new HtmlOutputText();
header.setValue(dynamicHeaders[i]);
column.setHeader(header);
HtmlInputText input=new HtmlInputText();
column.getChildren().add(input);
}
dynamicDataTableGroup = new HtmlPanelGroup();
dynamicDataTableGroup.getChildren().add(dynamicDataTable);
debugLogger.debug("populateDynamicDataTable:Exit");
}
public HtmlPanelGroup getDynamicDataTableGroup() throws Exception {
// This will be called once in the first RESTORE VIEW phase.
if (dynamicDataTableGroup == null) {
loadDynamicList(); // Preload dynamic list.
populateDynamicDataTable(); // Populate editable datatable.
}
return dynamicDataTableGroup;
}
public List<List<String>> getDynamicList() {
return dynamicList;
}
public void setDynamicList(List<List<String>> dynamicList) {
this.dynamicList = dynamicList;
}
public void setDynamicDataTableGroup(HtmlPanelGroup dynamicDataTableGroup) {
this.dynamicDataTableGroup = dynamicDataTableGroup;
}
public ValueExpression createValueExpression(String valueExpression, Class<?> valueType) {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().getExpressionFactory().createValueExpression(
facesContext.getELContext(), valueExpression, valueType);
}