In one form I have system OK button :
#Order(910.0)
public class SaveButton extends AbstractOkButton {
#Override
protected String getConfiguredLabel() {
return TEXTS.get("Save");
}
}
and I have tableField ...
If I add new empty row in this table execStore is called when pressing save button, but if I delete this empty row and press save button nothing is called, button only close form.
How to solve this? I would like to be able to delete empty row.
EDIT :
I figure it out that all rows where only smart fields are filled in, on delete it doesn't detect change. (not only empty rows...)
Problem is that checkSaveNeeded of the form return that nothing was changed in doOk method.
How do you add your row?
You can mark the row as inserted or not. See: addRow(newRow, markAsInserted); on the Table.
You second question is "How does a Table Field computes if the form needs to be stored or not"?
You can implement you custom logic on with execIsSaveNeeded(). See this question on the Scout forum:
https://www.eclipse.org/forums/index.php?t=msg&th=477037&goto=1042295#msg_1042295
Your last point is: when a row has the status ITableHolder.STATUS_NON_CHANGED in an editable table. When the value in a SmartColumn is changed with a SmartField, the status of the row is not changed to ITableHolder.STATUS_UPDATED.
I just tested it and it works as expected.
For row deletion, it depends on how your table field is configured. What is the value of the property isAutoDiscardOnDelete().
The doc here is still valid with Neon: Table > Delete a row from the table
With isAutoDiscardOnDelete() returning true (this is the case if getConfiguredAutoDiscardOnDelete() returns true), when you remove a row in your table field, it is discarded. There is nothing to save because there is no deleted row in the table field (Everything is explained in the wiki section I have mentioned)
If you want to persit a deletion on the server, you should not use discard the row but just delete it. This way you get the information in the FormData and from there you can work with the row status as described here: TableData (again old doc from our wiki, because it works like this since years. This it not new with Neon).
Related
A Vaadin grid shows data which is constantly updated by a background process. A user might select one or more rows to carry out various functions. The user might refresh the data from the backend (which updates rows shown in the grid).
The application needs to restore the selected items after a grid refresh.
grid.getSelectedItems() has to return the current instance of the selected items.
Refresh is implemented as follows:
void refresh() {
final var beanSet = grid.getSelectedItems();
dataProvider.refreshAll(); // refresh from backend
grid.asMultiSelect().select(beanSet); // restore previously selected items
}
Updating the grid works fine, but the selection is only partly restored: the "selected" checkbox is checked for the items in beanSet but querying grid.getSelectedItems() still returns the old instances.
Reproducer: https://github.com/skiedrowski/vaadin-grid-restore-selection, package com.example.application.views.idstyle -> check the notification after clicking "Update selected".
What is the correct way to update the selected items?
Context:
Vaadin Flow 23, Grid Pro in multiselect mode
grid items implement equals and hashCode based on an immutable id
grid data provider is a ConfigurableFilterDataProvider fetching paged data from backend
I believe the problem in your sample project is that you're always recycling a set of selected objects which contain the "old" data. You read out a reference to the old items in var beanSet = grid.getSelectedItems(); and store them back into the selection with grid.asMultiSelect().select(beanSet);
A lazy-loading Grid can't know if the programmatically set selection is a collection of objects that are available in the backend - it would need to fetch the entire backing dataset to do that. So when the selection is updated from the server, it could be any objects of the correct type, whether they actually exist in the data set or not.
What could do yourself is pass the selection set to the backend, update the items and then pass them back to the Grid's selection.
An open question that remains is whether Grid should update the selection when a fetch returns items that are equal to items in the selection. I can't immediately tell if that is
a) possible, or
b) a sensible thing to do
This is how we solve this in our application:
A]
fresh items are retrieved lazily
the only time when refreshed selection is needed is when we want to operate with the selected items (such as edit or another action, otherwise obsolete selected items don't matter)
the backend is able to return fresh item by ID
there is no need to update the selection on fetch() (which could introduce inconsistencies if a part of the selection is already updated but the rest haven't been fetched yet)
B]
we have some data providers which just hold wrappers for actual items
so any interaction with the items fetches fresh data under the hood
for the record, this was not done to solve this problem but mitigates it as a sideeffect
I am using a Vaadin Grid with buffered editing. I am adding an item to it as such:
items.add(hashMap);
dataProvider.refreshAll();
Then I attempt to edit the entry. I have these two editing buttons:
Button cancelButton = new Button(VaadinIcon.CLOSE.create(),
e -> editor.cancel());
Button saveButton = new Button(VaadinIcon.THUMBS_UP.create(),
e -> editor.save());
I also have saveListener which does the following:
dataProvider.refreshAll();
Without it, the grid does not update.
Anyhow. Here is the issue. If I edit, and I do not write any new data, the cancel and save button works the same. And I can re-edit. All is good.
However, when I edit and write any new data. I can save, but I cannot re-edit the entry I just saved.
If I add a new entry, I can now re-edit the entry that was locked before.
It is as if that entry is not part of the grid or the dataprovider because my addSelectionListener also does not react when I select that entry. Yet, I do find it in my item-list.
Furthermore, if I add a system.out to the editing component listener, nothing is shown in the log.
So what am I missing?
You serm to use Hashmap as data object instead of a POJO. That will require you to add unique "id" property to your map and override DataProvider to use it as an identity. See full code example here: https://cookbook.vaadin.com/grid-with-map
Hello i am working in a custom listener for click events in a table row in vaadin 7.
The problem is that the trigger jumps one time for every row there is on the table.
Is that the normal behaviour?
My code:
adding listener to the table
table.addItemClickListener(new MyCustomListener());
listener code:
public class MyCustomListener implements ItemClickListener {
#Override
public void itemClick(ItemClickEvent event) {
// TODO Auto-generated method stub
String id = event.getItem().toString();
System.out.println(id);//If the table has X rows this is printed X
//times even if i click a single time in a row
}
}
I created a minimum example with Vaadin in version 7.7.16 where I created a table, filled it with 3 entities and added your MyCustomListener. Whenever I click on a row, there is only fired one event only for the selected row. So no, this is not the normal behaviour. Are you sure that you only call addItemClickListener once on your table? You should check, that this method is only called once. Maybe you want to put a break point at
table.addItemClickListener(new MyCustomListener());
because if addItemClickListener is called multiple times, there will be multiple ActionListeners which are all executed (as the method name says it adds a listener). And it seems like you are adding as many new Listeners as the count of entities you have in your table.
I have seen there is a problem refreshing only current row if the data are changed in another form (and DataSet too) or even if the data are changed on server side (in trigger or from another user).
So i find solution that partially work with DevExpress's cxGrid and have following issue.
frm:=TfrmEdb01.Create(Self); // create edit-form
try
frm.LoadData(0); // do the insert in TAdQuery
frm.ShowModal; // Show edit form
// after closing an Edit-Form, make a new record in cxGrid
row:=tv01.dataController.InsertRecord(tv01.Controller.FocusedRecordIndex);
// for each column in grid...
for col:=0 to tv01.DataController.ItemCount-1 do
begin
// ...get its FieldName
sFld:=tv01.DataController.GetItemFieldName(col);
// and if this field exist in edit-form's Query
if frm.q01.FindField(sFld)<>nil then
//then assign this value to the newly created row in the grid.
tv01.DataController.Values[row,col]:=frm.q01.FieldByName(sFld).Value;
end;
finally
frm.Free;
end;
And realy, when I step out from the edit-form there is a New row created in the cxGrid. Problem is in that:
- if is double-clicked (to open edit-form again) then the previous record is opened. It seems to me the Data acctualy did not updated in Query object, only in GridView... maybe I should use values from Grid instead of Query object.
- if select another record (scroll them up and down), and then want to select again this new record, then it can not be focused at all. Only if I reload whole dataSet, then this new record can be selected same as any other.
Cheers!
p.s. To clearify a problem, I will provide whole test-project. There is also SQL script to create a table in the database, and AnyDac connection must be set to Your database.
There is also an image thate will/should ilustrate a problem.
You have call post to save the changes to the underlying dataset. Do it just before finally.
tv01.DataController.Post();
See the help for TcxCustomDataController.Post for more details.
What is the best way to replace a table row in Vaadin (6 and 7)? I use BeanItemContainer. The bean is an entity and has changed (not the ID).
I think this cause unnecessary method invocation and/or object creation:
table.removeItem( item );
table.addItem( item );
As I know, the best pratice is:
BeanItemContainer<DataModel> tableDataSource = new BeanItemContainer<>(DataModel.class);
table.setContainerDataSource(tableDataSource);
When you want to replace a row, just replace the data of this row in tableDataSource:
tableDataSource.removeItem(item);
tableDataSource.addItem(item);
The difference between your code and mine is:
In your code, you replace the row (it means the row is removed from the table and then a new row will be added to table).
In my example, I just replace the data of row.
Hope it helps