Nested Datatables Single Row Selection - jsf-2

I have multiple datatables whose are in single selection mode. I know how many datatables I have and how to reference to them because I append an index to their widgetVar attribute. So I can reference them by the "non-safe" operation var dt = eval('dt' + index).
The issue I am facing is every time I select a row in one of the nested dataTables the selection is remaining on the other ones and I want to clean them.
I've tried something like:
<p:ajax event="rowSelect" onstart="deseleccionarTablas()"/>
function deseleccionarTablas()
{
for (i=0; i < dtEstacionesSeleccionadas.getPaginator().cfg.rows; i++)
{
var dt = eval('dt' + i);
dt.unselectAllRows();
}
};
dtEstacionesSeleccionadas is the "container" or "root" table and works in "lazy" mode with paginator, so a variable number of nested dataTables may be shown. The code above doesn't work because it unselects everything, even the last row I selected, as expected. And I want that last one to remain selected.
Any ideas? Thank you.

Instead of using JavaScript, why don't you update them on the server side? Each table should have the selection="#{mrBean.selectedRow}" attribute. You only need to set all of those things to null in the actionListener of the <p:ajax event="rowSelect">. Then, a simple update="table1 table2 ... tablen" will solve you problem.

Related

JSF - how to properly use loops [c:forEach vs ui:repeat]

I'm trying to create a generic pageable table that will display any entity from database. I'm using annotations and reflection for that purpose. On the java side everything works fine, however I can't manage to create a view for my table. I tried two approaches, with c:forEach and ui:repeat:
Requirements for the view:
Fixed amount of records should be displayed on each page (eg. 10)
Components for browsing and editing table columns should be generated automatically based on viewed field type (field annotated in hibernate entity)
Additional column with actions should be added (removing, saving, filtering, adding entities)
Additional row for filtering and adding fresh entities should be added above table header
Each column has to be sortable
c:forEach approach problem:
When changing between pages that have different number of records, then proper records are displayed but number of rows is the same like on the previous page. If previous page had less records than next page will have less records than it should have and if previous page had more records than next page will have more records than it should have. However when I refresh the whole site on the given page everything renders properly.
On the first picture you can see, when I go to the last page unnecessary records are generated to match previous page size. On the second picture, page size is truncated to the last page size.
Table body code:
<tbody class="lot">
<c:forEach items="#{cc.attrs.wflBean.searchProvider.cells}" var="row" varStatus="rowStatus">
<tr>
<c:forEach items="#{row.cells}" var="cell" varStatus="cellStatus">
<td style="text-align: #{cell.alignment}; vertical-align: bottom;">
<h:commandLink action="#{cc.attrs.wflBean.editEntity}" value="Edit" styleClass="none"
rendered="#{cc.attrs.wflBean.isExternalEditSupported and cc.attrs.wflBean.canEdit}">
<f:setPropertyActionListener target="#{cc.attrs.wflBean.currentEntity}" value="#{cell.entity}"/>
</h:commandLink>
<!--TODO: cellIndex will not work properly for more then 10 columns/rows-->
<comp:pagableTableCell wflBean="#{cc.attrs.wflBean}" cell="#{cell}"
cellIndex="#{cellStatus.index}#{rowStatus.index}"
canEdit="#{not cc.attrs.wflBean.isExternalEditSupported and cc.attrs.wflBean.canEdit}"/>
</td>
</c:forEach>
...CODE FOR ADDING ADDITIONAL ACCTIONS...
</c:forEach>
</tbody>
pagableTableCell is a custom component that renders proper component for editing cell value it is done with c:choose/c:when/c:otherwise tags. When changing page, the cells are retrieved. Its done during RESTORE_VIEW and RENDER_RESPONSE phase. Cells for new page are recalculated and returned properly during RENDER_RESPONSE phase. Also, I read that c:forEach tag is evaluated during build view phase but I don't see what javax.faces.event.PhaseId is that? Page is set by another custom component and it is done properly right before RENDER_RESPONSE phase.
ui:repeat approach problem:
With this approach I replaced c:forEach with ui:repeat and c:choose/c:when/c:otherwise with ui:fragment but then, I can't evaluate EL expression within id attribute, to make it unique, for date component that you can see on images above. Unique id is required for date component to work properly. Is there any way to manually generate component id when using ui:repeat?
Overall I don't know how should I approach this problem. c:forEach seems to work better for me, at least table is usable. Could you advise me how to fix one of this problems?
Thanks,

Reset PrimeFaces DataTable state (filter, sorting, paging)

I'd like to reset the filter, sort and paging state of an PrimeFaces DataTable. Unfortunately, there is no easy way to do so. Especially reseting the sort state is difficult.
What I did until now is:
DataTable dataTable = (DataTable) FacesContext.getCurrentInstance().getViewRoot().findComponent(componentId);
if (dataTable != null) {
dataTable.setSortOrder("ascending"); // reset sortOrder
dataTable.setFirst(0); // reset page
dataTable.setFilteredValue(null); // reset filter
dataTable.setFilters(null);
}
I'm using PrimeFaces 3.4.1.
Finally, I found the solution, hidden in this sample http://www.primefaces.org/showcase/ui/data/datatable/columns.xhtml on tab ColumnsView.java:
table.setValueExpression("sortBy", null);
dataTable.setSortBy(null);
I'm using PrimeFaces 4.0
Inside the LazyDataModel load I call the method with this code:
DataTable dataTable = (DataTable) FacesContext.getCurrentInstance().getViewRoot().findComponent("form:dataTableItem");
dataTable.setFirst(0);
dataTable.reset();
dataTable.setSortBy(null);
First I reset the sort state as in the other answers:
dataTable.setSortBy(null);
However, this didn't reset the displayed codes in the table for me. It was still displaying the previously filtered results since I had set the filteredValue attribute on my datatable to a field in a view scoped bean. I fixed that problem by setting my filteredValue field to the value field, setting the current filtered results to the complete data set.
private DataTable filtervalue;
getter and setter of filtervalue ..........
call resetValue(); method on datatable
as filtervalue.resetValue();
Hope it works

Build table using partial view with Ajax requests

I need to dynamically create (insert) a new table row every time user presses button (using Ajax). My partial view structure:
<tr>
<td><td>
<td><td>
...
</tr>
When I need insert new row at the end I can do something like this:
element_table.innerHTML += ajax_data
But what I must do when I need to place it between other rows?
I can return only [td] elements and wrap them in [tr] clientside created element (tr.innerHTML = ajax_data) but I don't think this is a good idea.
Any ideas?
Are there any common practises?
The easiest way is to use jQuery with your Ajax response. It can be as simple as
$('#table').append(response)
to append a row. It's also possible to insert the new row at a specific index:
$('#my_table > tbody > tr').eq(index).after(response);
Note that index is 0 based.

How to set a column to be sorted on page load dynamically using DataTables.net?

Iam using Asp mvc. I have this table,which is a dataTables,
in my page, columns of the table sometimes appear or not, depending on the users authotrization.
e.g i have this table with checkbox(it appears dynamically and is on the left-most column), that i want to be not sortable.
i also wanted to sort the first column in the left on default.
So whether, checkbox appears or not, i want the first non-check box column to be sortable.
Is this possible?.
I know this question has been here for long, hopefully you got it resolved.
I am not sure I get it clearly, but my advise is that you look at this page for ideas on how you can control sorting using datatables.net:
http://www.datatables.net/release-datatables/examples/advanced_init/sorting_control.html
If you use one of the DataTools you can even control which columns show or give users the opportunity to select the columns they want to see.
Look at the examples here:
http://www.datatables.net/examples/
By this code you can sort individual columns on datatables by adding class 'sort-desc' or 'sort-asc' for sorting ascending and descending on page load
$('.dom-table').each(function(index) {
var sort_column=$('.dom-table thead tr').children().index('.sort-desc');
var sort_oper='desc';
if(sort_column < 0)
{
var sort_column=$('.dom-table thead tr').children().index('.sort-asc');
sort_oper='asc';
if(sort_column < 0)
{
sort_column=0;
}
}
$(this).dataTable({
"sDom": 'T<"clear">lfrtip',
"aaSorting": [[sort_column,sort_oper]],
});
});
I have not tested this code but it should work.

Maintain state of a dynamic list of checkboxes in ASP.NET MVC

I have a class called "PropertyFeature" which simply contains PropertyFeatureID and Description. It's a proper model created through LINQ to SQL mapped to an SQL Server database table. An example instance/row would be:
PropertyFeatureID: 2
Description: "Swimming Pool"
The number of rows (PropertyFeatures) can of course grow and shrink, and so I want to dynamically render a list of checkboxes so that the user can select any of them.
I can dynamically render the Checkboxes easily enough, with something like:
<%foreach (var Feature in (ViewData["Features"] as IEnumerable<MySolution.Models.PropertyFeature>)) { %>
<%=Html.CheckBox("Features", new { #id = Feature.PropertyFeatureID, #value = Feature.PropertyFeatureID })%><label for="Feature<%=Feature.PropertyFeatureID%>"><%=Feature.Description%></label>
<%}%>
I specify the ID for each checkbox and render the matching label so that the user can intuitively click the label and toggle the checkbox - that works great.
I set the CheckBox's "name" to "Features" so all the checkboxes render with the same name, and the MVC Model Binder piles them into a single collection called "Features" when the form is posted. This works nicely.
Once the form is submitted, I use the checked values and store them, so I need the actual integer values so I know which PropertyFeature is selected, not just a pile of Booleans and field names. So ideally, I want it as an array or a collection that's easy to work with.
I am able to retrieve the selected values from within my Controller method when the button is clicked because I have specified the parameter as int[] Features.
But the problem is that it doesn't maintain state. That is, when I click the submit button and the page reloads (with the form again displayed) I want all of the dynamic checkboxes to retain their checked status (or not). All of the other fields that I've created with Html.DropDownList and Html.TextBox all maintain their states successfully no problems at all on the same page in the same form.
I have spent hours reading all of the other threads and articles on similar issues and there is a lot of talk about using ICollection and IDictionary to bundle things up and include a Boolean value for each item so that it can maintain the checkbox state. But I don't 100% grasp how to use that in the context of my own personal example. I would like to keep the solution really simple and not have to code up pages of new classes just to maintain my checkbox state.
What is the cleanest and proper way to do this?
I got it working after much playing around with the various different approaches.
In the view:
<%string[] PostFeatures = Request.Form.GetValues("Features");%>
<% foreach (var Feature in (ViewData["AllPropertyFeatures"] as
IEnumerable<MySolution.Models.PropertyFeature>))
{ %>
<input type="checkbox" name="Features"
id="Feature<%=Feature.PropertyFeatureID.ToString()%>"
value="<%=Feature.PropertyFeatureID%>"
<%if(PostFeatures!=null)
{
if(PostFeatures.Contains(Feature.PropertyFeatureID.ToString()))
{
Response.Write("checked=\"checked\"");
}
}
%> />
<label for="Feature<%=Feature.PropertyFeatureID%>">
<%=Feature.Description%></label> <%
} %>
In the receiving controller method:
public ActionResult SearchResults(int[] Features)
This method has a number of advantages:
Allows labels to be clicked to toggle the corresponding checkboxes (usability).
Allows the Controller method to receive a super tidy array of ints, which ONLY contains the ints that have been selected - and not a whole other pile of items which were unselected or containing false/null/blank/0 etc.
Retains the checkbox's checked state when the page reloads containing the form, i.e. the user's selection is retained.
No random/stray type=hidden input fields created from the default ASP.Net MVC Html.CheckBox helper - I know it does those for a good reason, but in this instance, I don't require them as I only want to know about which IDs have been selected and for those to be in a single, tidy int[].
No masses of additional server side bloated classes, helpers and other happy mess required to achieve such a simple thing.
I would recommend this approach for anyone wanting the cleanest / bloat-free solution for a dynamic checkbox list where you need the IDs and you just want to get down to business!
The problem is that when you are rendering your list of checkboxes, you aren't setting any of them as selected. You will need to set your int[] Features in ViewData, and then in your foreach loop, check to see if the ID of that Feature is in the array in ViewData.
something like:
<%=Html.CheckBox("Features",
((int[])ViewData["SelectedFeatures"]).Contains(Feature.PropertyFeatureID),
new { #id = Feature.PropertyFeatureID, #value = Feature.PropertyFeatureID })%
although I didn't test it, so it might not be 100%.

Resources