This functionality was working in PF8 but after upgrading to PF10 it is now broken
Scenario as follows:
I have a main single selection datatable(Table 1, ekeys). I have a secondary multi selection datatable(Table 2, groupsTable) that displays a list of rows. Depending on the selection from Table1, i want to auto-select a number of rows in Table2 based on some business logic. This is working.
What is not working is that when I select a different row from Table1, Table 2 stills shows the rows associated to the previous selection AND the rows from the current selection. I can confirm that my logic in the controller has the expected values in the objects relating to the selection variable of Table2.
But the in the DataTableRender class i can see the rowkeys for that table still contain the rowkey for the previous selection. Then the new rowkeys are added and I see the combined set of highlighted rows. If i click a third row in Table1 then same happens again.
I have tried, calling the unselectAllRows method in the onstart of my <p:ajax command. But there appears a PF10 bug with unselectAllRows in that it does not clear the rowkeys value but rather just un-highlights the row.
I tried calling it from the java side but then it gets executed after the logic to the next selected row and so ends up clearing everything instead of the previous.
I created my own DataTableRenderer class and override a method and forced the rowkey of the table to null everytime. This worked but broke another use case where i have another Table1 but its multi-selection instead of single selection so i actually want the previous values kept!
I have tried setting the selectedEkey variable to null or empty but still the rows remain selected.
Running out of ideas on how to handle this. Primefaces seem to have decided to give you a pretty broken first major release and then charge you to fix the many regression bugs they introduce.
xhtml Table1
<h:form id="eKeyListForm">
<p:dataTable id="ekeys" value="#{eKeyController.lvList}"
var="ekey" selectionMode="single"
selection="#{eKeyController.selectedEKey}"
scrollable="true"
rows="25"
paginatorPosition="bottom"
paginator="true"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
currentPageReportTemplate="{startRecord}-{endRecord} #{i18n_layout.paginator_from} {totalRecords} | #{i18n_layout.paginator_page} {currentPage} #{i18n_layout.paginator_of} {totalPages}"
rowsPerPageTemplate="5,10,15,20,25"
resizableColumns="true"
rowKey="#{ekey.id}">
<p:ajax event="rowSelect" process="#this" update=":hw-editmenu:hw-emf :dlgSaveComp:dlgAskSaveForm :dlgDeleteComp:dlgAskDeleteForm :eKeyListForm :tabView:groupsForm:groupsTable" />
xhtml Table 2
<h:form id="groupsForm">
<hw:dataTable id="groupsTable"
widgetVar="groupsTable"
var="ug"
value="#{eKeyController.childGroups}"
selection="#{eKeyController.selChildGroups}"
rowKey="#{ug.id}"
multiselect="true"
rowSelectMode="add"
scrollable="false">
<p:ajax event="rowSelect" listener="#{eKeyController.onChildGroupRowSelect}" update=":hw-editmenu:hw-emf"/>
<p:ajax event="rowUnselect" listener="#{eKeyController.onChildGroupRowUnselect}" update=":hw-editmenu:hw-emf"/>
<p:ajax event="rowSelectCheckbox" listener="#{eKeyController.onChildGroupRowSelect}" update=":hw-editmenu:hw-emf"/>
<p:ajax event="rowUnselectCheckbox" listener="#{eKeyController.onChildGroupRowUnselect}" update=":hw-editmenu:hw-emf"/>
<p:ajax event="toggleSelect" listener="#{eKeyController.onChildGroupToggleSelect}" update=":hw-editmenu:hw-emf"/>
Backing Bean
public void setSelectedEKey(IEKey selectedEKey) {
if (!this.isChanged) {
this.selectedEKey = selectedEKey;
nextSelected = null;
refreshSelectedChildGroups();
} else {
this.nextSelected = selectedEKey;
PrimeFaces.current().executeScript("PF('dlgAskSaveWidget').show()");
}
}
private void refreshSelectedChildGroups() {
if (selectedEKey != null) {
this.setSelChildGroups(selectedEKey.getUserGroups());
} else {
this.setSelChildGroups(new ArrayList<>());
}
PrimeFaces.current().ajax().update(Arrays.asList("tabView:groupsForm:groupTable"));
}
Any thoughts on how to get the rowkey selection in Table2 cleared each time?
Related
We are currently migrating our application from Java6 to Java8.We use primefaces-4.0 and JSF 2.2 version.
Following is the code:
// Iterate over columns.
for (int i = 0; i < dynamicList.get(0).size(); i++) {
// Create <h:column>.
column = new Column();
// Create <h:outputText value="dynamicHeaders[i]"> for <f:facet name="header"> of column.
column.setHeaderText(dynamicHeaders[i]);
//column.setWidth("" + (100 / dynamicHeaders.length));
//dynamicDataTable.getChildren().add(column);
System.out.println("Table after setting values");
System.out.println("List size is:"+dynamicList.size());
System.out.println("First list size is:"+dynamicList.get(0).size());
System.out.println("Elements:"+dynamicList.get(0));
System.out.println(column.getHeaderText());
System.out.println(column.getChildren().get(i)); //Getting IndexOutOfBounds exception in this line
// Create <h:outputText value="#{dynamicItem[" + i + "]}"> for the body of column.
output = new OutputLabel();
output.setValueExpression("value", createValueExpression("#{dynamicItem[" + i + "]}", String.class));
column.getChildren().add(output);
System.out.println("Column information");
System.out.println(output.toString());
System.out.println(output.getValue());
System.out.println(output.getChildren().get(i));
System.out.println(output.getValueExpression("value"));
System.out.println(output.getChildren().size());
System.out.println(output.getFamily());
}
We are generating reports in Excel. When debugging code able to see IndexOutOfBounds Exception(have commented the line). In logs I'm able to print the list values and table is also constructed using primefaces. I'm facing issue only when setting value to the table.This works fine in Java6.
I'm unable to identify where the issue is.Kindly help.
I have a datatable with 10 columns which are grouped in 4:4:2 manner. Now the first two groups(of 4) are fixed while the last 2 can be added to any of the groups(single or both at a time) based on a condition.
Is there a way to set indexes for columns so that they can be ordered based on a condition ?
I see that Primefaces reorder using drag n drop gives the kind of result Im looking for except I want the reordering to be programmable and set before the table is displayed.
I had basically the same problem: after allowing the user to rearrange columns, it is easy to save the arrangement into a cookie, but how to restore the order a day later?
As far as I know, there are no primefaces method to this but can be hacked with a little javascript. (I tried with primefaces 6.0)
1) Give all the columns unique styleClasses, like:
styleClass="mystyle col0"
styleClass="mystyle col1"
styleClass="mystyle col2"
...
2) Convert the styleClass strings into valid css selectors, and store the required order of columns as an order of those, like:
".mystyle.col2,.mystyle.col0,.mystyle.col1"
Put it into a cookie, or store and get back as you like.
3) Write a javascript function to rearrange the cells into the required order:
function reorder() {
var o = getCookie('orderString');
var a = o.split(",");
for (var i = a.length - 1; i >= 0; i--) {
$(a[i]).each(function() {
$(this).prependTo($(this).parent())
});
}
}
function getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length === 2)
return parts.pop().split(";").shift();
}
(Don't use EL expressions to get back the order string from a backing bean, because it evaluates on page render, so won't update if the user rearranges the columns again.)
4) Execute reorder() "every time you need it".
You'll certainly need it on page loads:
$(document).ready(function() {
reorder();
});
but also on paging events, so add something like this:
<p:ajax event="page" oncomplete="reorder();" />
(And perhaps other times I've not met yet.)
I have a pretty straightforward question which google fails to give me the answer to :
I have an AdvancedDataGrid where i build the columns dynamically (variable number of columns) in ActionScript, and i want the dataTip to display the column headerText when the user hovers over a cell. Adobe's example dataTipFunction:
private function tipFunc(value:Object):String
{
if (value is AdvancedDataGridColumn)
return "Column Name";
// Use the 'name' property of the data provider element.
return "Name: " + value["name"];
}
But in this case the value is only an AdvancedDataGrid column if the user hovers over a column header? I want the dataTip to always show the headerText for that column. So if i have to use this function, then how do i get the column headerText for a cell?
And as i understand the dataTipField i can't really use it to statically equal column.headerText (dataTipField = headerText).
Anyone have any pointers on how i can achieve this? It seems like a really easy task, still i can't seem to find out how :)
You can use a different function per column, which could be anonymous:
<AdvancedDataGridColumn dataTipFunction="{function(value:Object):String{return 'Data Tip'}}" ... />
In my Windows Phone Mango app, I have a bunch of checkboxes, each corresponding to a day of the week. I want to filter the data I query by which checkboxes are checked. Here's what I've come up with, but I feel like there's a better solution:
Declare the checkboxes in XAML:
<CheckBox Content="Mon" x:Name="MonCheckbox" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap"/>
<CheckBox Content="Tue" x:Name="TueCheckbox" Grid.Column="1" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />
<CheckBox Content="Wed" x:Name="WedCheckbox" Grid.Column="2" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />
<CheckBox Content="Thur" x:Name="ThurCheckbox" Grid.Row="1" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />
<CheckBox Content="Fri" x:Name="FriCheckbox" Grid.Row="1" Grid.Column="1" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />
<CheckBox Content="Sat" x:Name="SatCheckbox" Grid.Row="1" Grid.Column="2" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />
<CheckBox Content="Sun" x:Name="SunCheckbox" Grid.Row="2" Grid.Column="0" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />
Associate a day with each checkbox:
public MainPage()
{
InitializeComponent();
LayoutRoot.DataContext = this;
// This is grossly imperative. Can it be done in XAML?
MonCheckbox.Tag = DayOfWeek.Monday;
TueCheckbox.Tag = DayOfWeek.Tuesday;
WedCheckbox.Tag = DayOfWeek.Wednesday;
ThurCheckbox.Tag = DayOfWeek.Thursday;
FriCheckbox.Tag = DayOfWeek.Friday;
SatCheckbox.Tag = DayOfWeek.Saturday;
SunCheckbox.Tag = DayOfWeek.Sunday;
// ...
}
Maintain a collection of the currently selected days:
ICollection<DayOfWeek> _selectedDays = new Collection<DayOfWeek>();
private void DayCheckbox_Tap(object sender, RoutedEventArgs e)
{
CheckBox checkbox = (CheckBox)sender;
if (_selectedDays.Contains((DayOfWeek)checkbox.Tag))
{
_selectedDays.Remove((DayOfWeek)checkbox.Tag);
}
else
{
_selectedDays.Add((DayOfWeek)checkbox.Tag);
}
refreshCheckinData();
}
The problem comes when I go to refresh the data that's displayed to the user:
private void refreshCheckinData()
{
Checkins.Clear();
Checkins.AddAll(from checkin in checkinData.Items
where _selectedDays.Contains(checkin.DateTime.DayOfWeek)
select checkin);
}
public static class ExtensionMethods
{
public static void AddAll<T>(this ICollection<T> dest, IEnumerable<T> source)
{
if (dest == null)
{
throw new ArgumentNullException("dest");
}
foreach (T t in source)
{
dest.Add(t);
}
}
}
When the code tries to iterate over source in AddAll(), the following exception occurs:
Method 'Boolean Contains(System.DayOfWeek)' has no supported translation to SQL." System.Exception {System.NotSupportedException}
How can I get around this? Why does Contains require a SQL translation? Is there a better approach to this whole thing, using more declarative XAML and less imperative code-behind?
Update: I tried changing the query to:
where _selectedDays.Any(day => day == checkin.DateTime.DayOfWeek)
now I get the following error:
"Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator." System.Exception {System.NotSupportedException}
_selectedDays is defined in memory. why does it need to be translated to SQL?
Your original query is close. I think the Contains() method on ICollection is getting in the way of the SQL translator -- I would need to double check the code to be sure.
You can work around this by forcing selection of the Enumerable.Contains() extension method by changing your code to this:
private void refreshCheckinData()
{
Checkins.Clear();
Checkins.AddAll(from checkin in checkinData.Items
where _selectedDays.AsEnumerable().Contains(checkin.DateTime.DayOfWeek)
select checkin);
}
Enumerable.Contains(T) extension method will translate into an IN clause in the database.
The resulting query will be something like this:
SELECT [t0].[Key], [t0].[Day]
FROM [Stuff] AS [t0]
WHERE [t0].[Day] IN (#p0, #p1)
If i understand it correctly then you wanna add all selected days to your 'Chekings' so why don't you try this code, i think this will solve your problem for now and to answer the other questions i have to think about them a bit a do some research. :)
foreach(var day in _selectedDays)
{
Checkins.AddAll(from checkin in checkinData.Items
where checkin.DateTime.DayOfWeek == day
select checkin);
}
Would have to test this one i don't know if it works or not or if it is even valid.
from checkin in checkinData.Items
join sdays in _selectedDays on checkin.DateTime.DayOfWeek == sdays
select checkin
i have a JTable with row filter.
once fitered if i didn't get any row then i have to show a string like "Nothing found to display " inside table as first row.
please do needful.
Thanks ,
Narasimha
I needed to solve this exact problem today and wasn't able to find a good answer online. In the end I came up with my own solution, which I think may be exactly what you want. I don't know if this is too late for your project, but perhaps it can help others:
JTable.paintComponent(Graphics g) will not be called unless the table has a height that is greater than 0. This causes a problem for empty tables, so we expand the JTable height if needed so that it will always be at least the size of the JViewport that is it's parent.
JTable tableName = new JTable() {
public boolean getScrollableTracksViewportHeight() {
if(getParent() instanceof JViewport)
return(((JViewport)getParent()).getHeight() > getPreferredSize().height);
return super.getScrollableTracksViewportHeight();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(getRowCount() == 0) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLACK);
g2d.drawString("Nothing found to display.",10,20);
}
}
}
containerName.add(new JScrollPane(tableName));
To show a line of text in the multicolumn table can be quite difficult, the span AFAIK is not supported.
One possibility would be to hide all data columns (to show them later you have to memorize them somewhere) and show one column for the message.
An easier way would be to create a JPanel with CardLayout, add 2 cards - one containing table and one containing your empty data warning. If the filter returns empty result, show the card with empty warning, in other case - show the table.
If the filter has excluded all rows, the result returned by getViewRowCount() will be zero. You can update the GUI accordingly; setToolTipText() is handy if screen space is lacking.
Here's an example:
TableModel model = ...
JTable table = new JTable(model);
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
JScrollPane pane = new JScrollPane(table);
JLabel label = new JLabel("");
...
String s = "Rows: " + sorter.getViewRowCount()
pane.setToolTipText(s);
label.setText(s);