I want one of my table columns to have a deleteButton.
ActionCell<Entrata> deleteCell = new ActionCell<Entrata>("x",new Delegate<Entrata>() {
#Override
public void execute(Entrata object) {
// rpc stuff....
}
});
Ok but this line generates an error:
Column<Entrata,Entrata> deleteColumn = new Column<Entrata, Entrata>(deleteCell);
"Cannot instantiate the type Column"
What do you think?
Here you go with working code:
Assumptions:
TYPE - Is the class of the data you show in rows of Cell Table it the same because I assume you want reference to the instance of data when you going to delete it
public class DeleteColumn extends Column<TYPE, TYPE>
{
public DeleteColumn()
{
super(new ActionCell<TYPE>("Delete", new ActionCell.Delegate<TYPE>() {
#Override
public void execute(TYPE record)
{
/**
*Here you go. You got a reference to an object in a row that delete was clicked. Put your "delete" code here
*/
}
}));
}
#Override
public TYPE getValue(TYPE object)
{
return object;
}
};
From the doku:
A representation of a column in a table. The column may maintain view data for each cell on demand. New view data, if needed, is created by the cell's onBrowserEvent method, stored in the Column, and passed to future calls to Cell's
So you have to declar it something like this:
Column<String, String> colum = new Column<String, String>(null) {
#Override
public String getValue(String object) {
// TODO Auto-generated method stub
return null;
}
};
Still I don't exactly know how you implement the delete button, so it would be nice if you can give us the rest of your code.
This works
//table = initialized CellTable with content already loaded
ActionCell editCell = new ActionCell<EmployeeObject>("remove", new ActionCell.Delegate<EmployeeObject>() {
public void execute(EmployeeObject object){
List<EmployeeObject> list = new ArrayList<EmployeeObject>(table.getVisibleItems());
for(int i = 0; i < list.size(); i ++){
if(object.getFirstname().equals(list.get(i).getFirstname())){
list.remove(i);
break;
}
}
table.setRowData(list);
}
});
Column<EmployeeObject, ActionCell> editColumn = (new IdentityColumn(editCell));
Related
I want to implement a row deletion logic in a Nebula Nattable.
This is what I plan to do:
Add context menu to the Nattable which is described in http://blog.vogella.com/2015/02/03/nattable-context-menus-with-eclipse-menus/
Add an SWT Action to the menu which will implement the delete
my question is, which is the best way to accomplish this:
Should I delete the corresponding value from my data model and the table view is refreshed when I execute this.natview.refresh();?
OR
Should I get the rows from SelectionLayer and delete them (if so how do I do ?)?
OR
is there any default support for this function through IConfiguration?
In NatTable you would typically do the following:
Create a command for deleting a row
public class DeleteRowCommand extends AbstractRowCommand {
public DeleteRowCommand(ILayer layer, int rowPosition) {
super(layer, rowPosition);
}
protected DeleteRowCommand(DeleteRowCommand command) {
super(command);
}
#Override
public ILayerCommand cloneCommand() {
return new DeleteRowCommand(this);
}
}
Create a command handler for that command
public class DeleteRowCommandHandler<T> implements ILayerCommandHandler<DeleteRowCommand> {
private List<T> bodyData;
public DeleteRowCommandHandler(List<T> bodyData) {
this.bodyData = bodyData;
}
#Override
public Class<DeleteRowCommand> getCommandClass() {
return DeleteRowCommand.class;
}
#Override
public boolean doCommand(ILayer targetLayer, DeleteRowCommand command) {
//convert the transported position to the target layer
if (command.convertToTargetLayer(targetLayer)) {
//remove the element
this.bodyData.remove(command.getRowPosition());
//fire the event to refresh
targetLayer.fireLayerEvent(new RowDeleteEvent(targetLayer, command.getRowPosition()));
return true;
}
return false;
}
}
Register the command handler to the body DataLayer
bodyDataLayer.registerCommandHandler(
new DeleteRowCommandHandler<your type>(bodyDataProvider.getList()));
Add a menu item to your menu configuration that fires the command
new PopupMenuBuilder(natTable)
.withMenuItemProvider(new IMenuItemProvider() {
#Override
public void addMenuItem(NatTable natTable, Menu popupMenu) {
MenuItem deleteRow = new MenuItem(popupMenu, SWT.PUSH);
deleteRow.setText("Delete");
deleteRow.setEnabled(true);
deleteRow.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent event) {
int rowPosition = MenuItemProviders.getNatEventData(event).getRowPosition();
natTable.doCommand(new DeleteRowCommand(natTable, rowPosition));
}
});
}
})
.build();
Using this you don't need to call NatTable#refresh() because the command handler fires a RowDeleteEvent. I also don't suggest to call NatTable#refresh() in such a case, as it might change and refresh more than it should and would not update other states correctly, which is done correctly by firing the RowDeleteEvent.
Note that the shown example deletes the row for which the context menu is opened. If all selected rows should be deleted, you should create a command handler that knows the SelectionLayer and retrieve the selected rows as shown in the other answer.
In our application we do the following:
Get selected row objects:
SelectionLayer selectionLayer = body.getSelectionLayer();
int[] selectedRowPositions = selectionLayer.getFullySelectedRowPositions();
Vector<Your Model Objects> rowObjectsToRemove = new Vector<Your Model Objects>();
for (int rowPosition : selectedRowPositions) {
int rowIndex = selectionLayer.getRowIndexByPosition(rowPosition);
rowObjectsToRemove .add(listDataProvider.getRowObject(rowIndex));
}
Remove them from the data provider
call natTable.refresh()
I want to know if user clicked on header for Ascending or Descending sorting.
How can I find that?
Regards
Try this:
1) create SortHandler and attach to your grid
ColumnSortEvent.AsyncHandler sortHandler= new ColumnSortEvent.AsyncHandler(grid);
grid.addColumnSortHandler(sortHandler);
ColumnSortList columnSortList = grid.getColumnSortList();
2) create your Column (TextColumn etc) such as:
TextColumn<Dog> yourTextColumn = new TextColumn<Dog>() {
#Override
public String getValue(String object) {
return object;
}
}
3) create your Header
Header yourHeader = new Header() {
#Override
public Object getValue() {
return value; // here return header value
}
}
3) add column to grid and push a ColumnSortInfo onto the list
grid.addColumn(yourTextColumn, yourHeader);
columnSortList.push(new ColumnSortList.ColumnSortInfo(yourColumn, true));
You can always look here for more useful examples.
in order to get the direction of the ordering, all you have to do is to get the ColumnSortList and call method #get(0) with zero index. as documentation of ColumnSortList says the "The 0th item is the {#link ColumnSortInfo} of the most recently sorted * column.". so the returned object (which is ColumnSortList.ColumnSortInfo) contains information about last clicked Column and it has a method called #isAscending() which is a flag to identify the direction.
the sample code:
ColumnSortList sortList = dataGrid.getColumnSortList();
ColumnSortList.ColumnSortInfo info = sortList.get(0);
also want to note that this code block should be in AsyncDataProvider#onRangeChanged.
there is also an alternative to this, consider the following:
columnSortHandler = new ColumnSortEvent.AsyncHandler(table) {
#Override
public void onColumnSort(ColumnSortEvent event) {
List<T> newData = new ArrayList(table.getVisibleItems());
if (event.isSortAscending()) {
Collections.sort(newData, (Comparator)event.getColumn());
} else {
Collections.sort(newData, (Comparator)event.getColumn());
Collections.reverse(newData);
}
table.setRowData(newData);
}
};
table.addColumnSortHandler(columnSortHandler);
I want to add double click handler to FlexTable in GWT.
I used below code :
flexTable.addDoubleClickHandler(new DoubleClickHandler() {
#Override
public void onDoubleClick(DoubleClickEvent event) {
}
});
But how can i get row index.
Please suggest me.
Sadly there is no built-in method to retrieve a cell from a double-click event in FlexTable. It can be implemented in a few lines though. This is how I did it.
Create a subclass of FlexTable with the following code:
public class DoubleClickTable extends FlexTable {
class MyCell extends Cell {
protected MyCell(int rowIndex, int cellIndex) {
super(rowIndex, cellIndex);
}
}
public Cell getCellForEvent(MouseEvent<? extends EventHandler> event) {
Element td = getEventTargetCell(Event.as(event.getNativeEvent()));
if (td == null) {
return null;
}
int row = TableRowElement.as(td.getParentElement()).getSectionRowIndex();
int column = TableCellElement.as(td).getCellIndex();
return new MyCell(row, column);
}
}
Then in the DoubleClickHandler call getCellForEvent() to retrieve the clicked cell:
flexTable.addDoubleClickHandler(new DoubleClickHandler() {
#Override
public void onDoubleClick(DoubleClickEvent event) {
Cell cell = flexTable.getCellForEvent(event);
GWT.log("Row index: " + cell.getRowIndex());
}
});
Implementation details: method getCellForEvent() is a copy of the method with the same name in class HTMLTable (the parent class of FlexTable), except that it has a different signature for the parameters. The MyCell class is a workaround to be able to call the Cell constructor, which is protected.
I am using CellTable to add columns to it.
It works fine when I add rows and single data on each cell.
It has header like Name ,Age, Address with rows below it which contains the values
I now want to have a Actions cloumn in the last with two buttons (Edit and Delete Button) in single cell in on the rows below this column and to capture the button click events acordingly.
Name Age Address Actions
A 15 123 Edit Delete
B 20 578 Edit Delete
C
Could you please let me know how to do it.
Thanks
There are two ways to achieve that:
Subclass AbstractCell and implement the render method to create two buttons and handle its events (see here for more details).
Use a CompositeCell to add two ActionCells
Second approach is easier and cleaner. Here is the code for that:
public void onModuleLoad() {
CellTable<Person> table = new CellTable<Person>();
List<HasCell<Person, ?>> cells = new LinkedList<HasCell<Person, ?>>();
cells.add(new ActionHasCell("Edit", new Delegate<Person>() {
#Override
public void execute(Person object) {
// EDIT CODE
}
}));
cells.add(new ActionHasCell("Delete", new Delegate<Person>() {
#Override
public void execute(Person object) {
// DELETE CODE
}
}));
CompositeCell<Person> cell = new CompositeCell<Person>(cells);
table.addColumn(new TextColumn<Person>() {
#Override
public String getValue(Person object) {
return object.getName()
}
}, "Name");
// ADD Cells for Age and Address
table.addColumn(new Column<Person, Person>(cell) {
#Override
public Person getValue(Person object) {
return object;
}
}, "Actions");
}
private class ActionHasCell implements HasCell<Person, Person> {
private ActionCell<Person> cell;
public ActionHasCell(String text, Delegate<Person> delegate) {
cell = new ActionCell<Person>(text, delegate);
}
#Override
public Cell<Person> getCell() {
return cell;
}
#Override
public FieldUpdater<Person, Person> getFieldUpdater() {
return null;
}
#Override
public Person getValue(Person object) {
return object;
}
}
The solution above is perfect!THX.
In addition: If you liked to design the buttons in the ActionCell, then you could do this -> In the constructon of the class you can build a html input and in "class" attribute, you can add a css style, which will be used.:
public ActionHasCell(String text, Delegate<Person> delegate) {
cell = new ActionCell<Person>(text, delegate) {
public void render(Context context, Person person, SafeHtmlBuilder sb)
{
SafeHtml html = SafeHtmlUtils.fromTrustedString("<input type=\"button\" value=\"anynameyouwant\" class=\"cssstylename\" />");
sb.append(html);
}
};
}
This time you don't need the String, but you can pass parameters and use them to build the button.
Assuming that data retrieves from DataStore using RPCproxy, populate to grid using ListStore upon opening the page.
Then, there's a form to add an entity and after modification it will reflect the new list in GXT grid with the new added row.
How can reload the grid? I tried .reconfigure() method in Grid but didn't work.
grid.getStore().getLoader().load();
update:
First of all you must extract Grid before your Proxy, and the second thing is to change your RPC callback:
public class PagingBeanModelGridExample extends LayoutContainer {
//put grid Class outside a method or declare it as a final on the begin of a method
Grid grid = null;
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
RpcProxy> proxy = new RpcProxy>() {
#Override
public void load(Object loadConfig, final AsyncCallback> callback) {
//modification here - look that callback is overriden not passed through!!
service.getBeanPosts((PagingLoadConfig) loadConfig, new AsyncCallback>() {
public void onFailure(Throwable caught) {
callback.onFailure(caught);
}
public void onSuccess(PagingLoadResult result) {
callback.onSuccess(result);
//here you are reloading store
grid.getStore().getLoader().load();
}
});
}
};
// loader
final BasePagingLoader> loader = new BasePagingLoader>(proxy, new BeanModelReader());
ListStore store = new ListStore(loader);
List columns = new ArrayList();
//...
ColumnModel cm = new ColumnModel(columns);
grid = new Grid(store, cm);
add(grid);
}
}
To display the new data to grid do you really need to reload the grid?
You can create a new model object with the new data and add this to the ListStore.
Suppose you have a CommentModel which extends the BaseModel and a ListStore of Comment model commentStore.
final ListStore<Commentmodel> commentStore = new ListStore<Commentmodel>();
//now call a rpc to load all available comments and add this to the commentStore.
commentService.getAllComment(new AsyncCallback<List<Commentmodel>>() {
#Override
public void onFailure(Throwable caught) {
lbError.setText("data loading failure");
}
#Override
public void onSuccess(List<Commentmodel> result) {
commentStore.add(result);
}
});
commentService is an AsyncService.
Now if a user post a comment, just create a new CommentModel object with the new data
CommentModel newData = new CommentModel('user name', 'message','date');
And add this to the commentStore.
commentStore.add(newData);
Hope this will serve you purpose.
But if you really need to reload the whole set of data, call the service again. In the onSuccess method first clear the commentStore then add result. Remember this is more more time consuming that the 1st approach.