Empty h:dataTable in JSF renders empty row with invalid number of columns? - jsf

I have the following JSF code which renders a table from a Bean which might be empty
<h:dataTable value="#{recController.currentRecList}" var="rec" styleClass="display" id="rec">
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['rec.name']}"/>
</f:facet>
#{rec.name}
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['rec.notes']}"/>
</f:facet>
#{rec.notes}
</h:column>
</h:dataTable>
problem is the above code renders the following HTML:
<tbody><tr><td></td></tr></tbody>
The above is wrong because it should render:
<tbody><tr><td></td><td></td></tr></tbody>
where the number of columns is two and not one! but even better it should render just:
<tbody></tbody>
So that DataTables js script recognizes there's no rows and shows a nice "Empty table".
Currently DataTables js script returns an error:
DataTables warning: table id=rec - Requested unknown parameter '1' for row 0.
For more information about this error, please see http://datatables.net/tn/4
of course because it sees a row but with an incorrect number of columns.
Now using Primefaces p:dataTable produces even more boilerplate html code because the table is buried inside several div's and when an empty result is returned it produces a:
<tr class="ui-widget-content ui-datatable-empty-message">
<td class=" " colspan="4">No records found.</td>
</tr>
So again DataTables js (http://datatables.net/) finds a wrong number of columns.
Is there a way to tell primefaces what html code to output when no result is found?

Ok I finally found a workaround by using jQuery to check the html and remove the offending column, this is rather hacky but seems noone has any workaround and both standard JSF datatable and Primefaces datatable have the same issue.
<script type="text/javascript" charset="utf-8">
var oTable;
jQuery(document).ready(function() {
/* JSF has a bug where in the case of an empty list it generates a table with
* a single row and a single column no matter how many columns where defined.
* This breaks DataTables script so we manually delete this offending row if
* it is present */
length = jQuery("#myTable tbody tr").first().children().length;
alert(length);
if(length===1)
{
jQuery("#myTable tbody").html("");
}
oTable = jQuery('#myTable').dataTable({
"sDom": 'TRlfrCtip',
"oTableTools": {
"sSwfPath": "#{resource['tabletools/swf/copy_csv_xls_pdf.swf']}"
}
});
//fnClickAddRow();
});
</script>

Related

Primefaces Ajax Datatable rowSelect only firing on some whitespace [duplicate]

I'm having a PrimeFaces (3.5) DataTable which contains some columns with <p:cellEditor> as usual in which selection of multiple rows is enabled by selectionMode="multiple".
When I click on a cell in a row containing <p:cellEditor>, the row is selected only time to time. The selection of the row is possible only when the padding area close to the cell borders is clicked. The selection is not made, when the actual text of that cell in the middle is clicked which is actually enclosed by <p:cellEditor>.
This doesn't happen, when <p:cellEditor> is dismissed.
Selection of a row in this manner is essential in my case , since a single row is deleted with a context menu by right-clicking on the row to be deleted exactly the same as this showcase example (that example works fine because it doesn't have <p:cellEditor>. I don't find a showcase example that uses both row selection and cell-editor together).
This issue was reported and its status is 'WontFix'. They said,
Cell and Row selection at same time is not supported.
But downgrading the framework from 3.5 indeed works (therefore, the above quote should simply be false and it appears to be misinterpreted) but this is not a solution. Did someone encounter this issue? Is there a way to change this behaviour?
Well, it has been 4 years and it hasn't been fixed yet. But - you can use some of JS magic in order to make it work.
First define JS function which selects datatable row by index:
<script>
function selectCurrentRow(index) {
var table = PF('myTableWidgetVar');
table.unselectAllRows();
table.selectRow(index, false);
}
</script>
Then define your datatable with rowIndexVar attribute set:
<p:dataTable id="myTable" widgetVar="myTableWidgetVar" var="parameter"
value="#{serviceMB.parameters}"
rowIndexVar="rowIndex"
rowKey="#{parameter.id}"
selectionMode="single"
editMode="cell">
And wrap cellEditor fields inside a div with onclick function defined:
<p:column>
<p:cellEditor>
<f:facet name="output">
<div onclick="selectCurrentRow(#{rowIndex});">
<p:outputLabel value="#{parameter.value}"/>
</div>
</f:facet>
<f:facet name="input">
<div onclick="selectCurrentRow(#{rowIndex});">
<p:inputText value="#{parameter.value}"/>
</div>
</f:facet>
</p:cellEditor>
</p:column>
This hack wont work properly if you are using row grouping datatable (row indexes will be shifted).
EDIT:
Use this function if you're using row grouping datatable:
function selectByRowKey(rowKey, table) {
for (var i = 0; i < table.rows.length; i++) {
var row = table.rows.get(i);
if (row.getAttribute("data-rk") === rowKey) {
table.unselectAllRows();
table.selectRow(i, false);
break;
}
}
}
Where table = PF('myTableWidgetVar') and rowKey is a currently selected rowKey (for example '#{parameter.id}').
USE: style="display: block" in your cell:Editor, works for me.
<p:cellEditor>
<f:facet name="output"><h:outputText style="display: block;" value="#{whatever}"/></f:facet>
<f:facet name="input"><p:inputText id=......../></f:facet>
</p:cellEditor>

How do I get h:outputText inside of a ui:repeat nested in h:dataTable to update when the datatable is updated?

So the relevant sections of my code is:
<h:panelGroup id="pnlGrp" style="padding:10px" width="100%">
<div>
<h:dataTable id="availableCrList"
value="#{searchData.availableCrList}"
var="avail"
varStatus="thisVarStatus" rows="#{searchData.rowsPerPage}"
sortColumn="#{searchData.crSortColumnName}"
sortAscending="#{searchData.crAscending}" style="width:100%;">
<h:column>
<ui:repeat value="#{avail.crRsnCdList}"
var="crRsnCd"
varStatus="status">
<h:outputText value="#{crRsnCd}<br />"
title="#{avail.crRsnDescList[status.index]}"
escape="false"/>
</ui:repeat>
</h:column>
</h:dataTable>
</div>
</h:panelGroup>
I'm working inside a legacy application and my goal is to display a list of codes which indicate reasons why a given item in this table might be completed, or cancelled, et cetera. The title is converted into a hovering tooltip which displays the description for each of these codes.
Now, I managed to get this working for singular codes no problem, but since switching from a String to a List of strings it's been a nightmare trying to get this to work.
Right now with the above code it displays the codes correctly the first time, but when I update the datatable by searching for a new value all the other columns (not shown) are correctly displayed while the RsnCd column continues to display the same data from the first search.
As an example, the first time I search for records the datatable might pull up:
Row1:A1
Row2:A1
Row3:A1
A3
Row4:A1
The second time I search for data I would expect to see only:
Row1:
Row2:
Row3:
Row4:
Row5:
Row6:
Row7:
But instead I get:
Row1:A1
Row2:A1
Row3:A1
A3
Row4:A1
Row5:
Row6:
Row7:
Really not sure if I'm explaining this adequately/understandably.
I solved this issue by changing
<ui:repeat value="#{avail.crRsnCdList}"
var="crRsnCd"
varStatus="status">
<h:outputText value="#{crRsnCd}<br />"
title="#{avail.crRsnDescList[status.index]}"
escape="false"/>
</ui:repeat>
To:
<ice:column>
<ice:repeat value="#{avail.crRsnCdList}"
varStatus="status">
<ice:outputText value="#{avail.crRsnCdList[status.index]}<br />"
title="#{avail.crRsnDescList[status.index]}"
escape="false"/>
</ice:repeat>
</ice:column>
I tried getting rid of the value but it stopped displaying anything.

How to bold specific Strings in an h:column

I have a JSF data table that is displaying data based off a search successfully. However, I'm not sure how to selectively bold certain text data in a particular column.
So, for instance, I would like this text...
Here is some text that would be inside the h:column
to show up like this on the page...
Here is some text that would be inside the h:column
Here's what my data table looks like
Results:
<h:dataTable var="results"
value="#{logSearcherBean.results}"
border="1">
<h:column>#{results.logName}</h:column>
<h:column>#{results.matchLine}</h:column>
</h:dataTable>
You could either homebrew an EL function which manipulates the column value and returns the desired HTML,
<h:outputText value="#{my:highlight(results.logName, logSearcherBean.query)}" escape="false" />
(note that this is due to escape="false", which is mandatory to present HTML literally, also sensitive to XSS attacks if the logName is a value which is fully controlled by the enduser)
Or grab JavaScript/jQuery which manipulates the returned HTML, see also this related question: Highlight a word with jQuery.
Hi all,
<p:column id="lastName"
headerText="Last Name">
<h:outputText value="#{person.lastName}" style="#{myBean.getStyle(person.lastName)}"/>
</p:column>
And in the bean:
public String getStyle(String str) {
return str.equals(keyword) ? "background-color: yellow" : "";
}
All best and happy coding!

jsf repeat inside datatable

I'm using datatable and i get number of columns dynamically. I tried to put repeat inside like this way:
<h:dataTable value="#{movieUserBean.sits}" var="row"
rowClasses="oddRows,evenRows" headerClass="header"
styleClass="table" cellpadding="5" cellspacing="0">
<ui:repeat value="#{row}" var="sit">
<h:column>
<h:selectBooleanCheckbox value= "#{movieUserBean.checked[sit.id]}"/>
</h:column>
</ui:repeat>
Which sits is a two dimensions array, my thought was that datatable should loop over the sits rows and repeat loops over every value inside every row (which is an object named Sit with get method: getId).
The problem is that I get an empty table. Seems like var "sit" is not getting value.
Can the problem be the fact that datatable ignores any elements who's not in column scope?
ui:repeat is called before the render response phase, i suggest you to use DynamicColumns of primefaces http://www.primefaces.org/showcase/ui/datatableDynamicColumns.jsf
A simple solution would be
<table>
<ui:repeat value="#{movieUserBean.sits}" var="row">
<tr>
<ui:repeat value="#{row}" var="sit">
<td><h:selectBooleanCheckbox value= "#{movieUserBean.checked[sit.id]}"/></td>
</ui:repeat>
</tr>
</ui:repeat>
</table>
If you have variable columns per row it might mess up with css styles. For example 5 columns on row one and 3 columns on row 2, how would you style them. The way i see it you want to show seats in a theater occupied with a checkbox.
You can try using ui:repeat's with ul,li or div's instead of going with the table. approach.

JSF - What happens if value EL expression evaluates to null?

What will happen if the EL expression like #{bean.list} is null. I've a nested datatable and the "value" of dataTable evaluates to null. In below example if issuerList is null, outer table footer is displayed but not the inner table. How does #{Issuer.issue} is handled considering "Issuer" is null !!!
Ex:
<h:datatable value="#{bean.issuerList}" var="issuer" >
..
<h:datatable value="#{issuer.issueList}" var="issue" >
....
....
<f:facet name="footer">
This is inner footer
</f:facet>
</h:datatable>
<f:facet name="footer" >
This is outer footer
</f:facet>
</h:datatable>
If the #{bean.issuerList} is null then there are simply no rows to render. Since the nested datatable (and its footer) is part of a row, it's also never rendered. You would need at least one row to get the nested datatable (and its footer) to render. The footer of the outer datatable is not part of any row, so it's always rendered.

Resources