Vaadin grid - change component column in one row only - vaadin

I have a grid with several columns. For three columns i used the column renderer. Each of the columns contains one button.
If i click one of those buttons, i want to replace the three buttons in that specific row with two other buttons. All the other rows should not be affected. Is this possible in a Vaadin grid?

Components in different columns don't know each other, as they are all defined in a separate scope (in the componentRenderer of their own column. You cannot define the Button outside of the componentRenderer as you found out in another question today). So the "obvious" solution won't work, where you add a clickListener on the Button to directly change the other buttons.
If you had one column with 3 Buttons inside then this would be much easier.
There is a way, but I see this more as a hack than as a solution. Because you need some extra implementation in the item class for this to work.
In the ComponentRenderer, you can add an if-statement where you look at some value of the item. In one case, you'll render button 1, in the other case you'll render the other button. And in the click listeners of the button you change that value in the item and refresh the dataprovider, so the componentRenderer is invoked again. It will now see the value on the item has changed, therefore displaying some other Button.
Here is some code to show what I mean:
// grid item class
public class Foo {
private boolean buttonPressed = false;
public Foo(){
}
public isButtonPressed(){
return buttonPressed;
}
public setButtonPressed(boolean buttonPressed){
this.buttonPressed = buttonPressed;
}
}
// adding of button columns
// do this 3 times for a test of your scenario.
grid.addComponentColumn(item -> {
if(!item.isButtonPressed()){
return new Button("Before Button was Pressed", click -> {
item.setButtonPressed(true);
grid.getDataProvider().refresh(item);
});
} else {
return new Button("Button was Pressed", click -> {
item.setButtonPressed(false);
grid.getDataProvider().refresh(item);
})
}
})

Related

How to set different select items in Vaadin Grid Pro's editComponent based on row item

I have Grid Pro displaying Products. A single column is configured as an EditColumn of type 'select' (dropdown/combobox). I'm trying to set the items for this component based on the Product of that row. Is this possible using the 'select' editColumn?
I tried to achieve what I want using the grid's 'addCellEditStartedListener' event, but I can't seems to access the editComponent from CellEditStartedEvent..
thx!
Yes, the this is missing feature in CellEditStartedEvent. As an alternative you can use custom editor in your edit column, as then you have reference to the field you are using, see example
// Use custom editor
EmailField emailField = new EmailField();
emailField.setWidth("100%");
emailField.addThemeName("grid-pro-editor");
grid.addEditColumn(Person::getEmail)
.custom(emailField, (item, newValue) -> {
item.setEmail(newValue);
}).setHeader("E-mail ");
// Use edit started listener to set the field conditionally enabled
grid.addCellEditStartedListener(event -> {
if (!event.getItem().isSubscriber()) {
emailField.setReadOnly(true);
} else {
emailField.setReadOnly(false);
}
});
Full code here: https://cookbook.vaadin.com/grid-pro-conditional-edit

How to add click listener or context menu to Vaadin's Grid column Header

This question is similar to this. But I'm interested in Vaadin 14 as I am migrating old Table components to Grids. There no longer a HeaderClickListener. Therefore, how can you implement click listener on Grid header.
I don't mind adding a context menu with a column selection for copying, but as I understand it, there is no API to get data in a column?
In Vaadin 14 there is no HeaderClickListener. Instead you need to do something like this:
Column<MyBean> column = grid.addColumn(..)
HeaderRow headerRow = this.getHeaderRows().get(0); // Get first header row
Div component = new Div(); // Just example, anything that has click listener can be used
component.setText("Header");
headerRow.getCell(column).setComponent(component);
component.addClickListener(..);
Alternatively you can use GridContextMenu
grid.addColumn(..).setId("column");
GridContextMenu<MyBean> menu = grid.addContextMenu();
item.addMenuItemClickListener(event -> {
Notification.show(selectedColumn);
});
menu.addGridContextMenuOpenedListener(event -> {
// item is not present when clicking header
if (!event.getItem().isPresent()) {
event.getColumnId().ifPresent(id -> {
selectedColumn = id;
});
} else {
menu.close(); // Do not let menu open on body
}
});

Vaadin addComponentColumn only works in last row

this.grid = new Grid<>(Person.class);
this.grid.setItems(personList);
this.grid.setSelectionMode(SelectionMode.MULTI);
this.grid.removeAllColumns();
this.grid.setColumns("firstname");
this.editButton = new Button(null, ImageIcons.EDIT.create());
this.editButton.getStyle().set("color", "#000000");
this.grid.addComponentColumn(person -> this.editButton);
this.deleteButton = new Button(null, IronIcons.DELETE_FOREVER.create());
this.deleteButton.getStyle().set("color", "#000000");
this.grid.addComponentColumn(person -> this.deleteButton);
this.addComponentAsFirst(this.grid);
I have a personList with several entries. The grid shows all these entries with their first name. But it only shows the buttons in the last row. What is the problem?
You use the very same Button instance for each row. You should create a new Button within the componentRenderer, so each row will have its own Button.
Try it like this:
this.grid = new Grid<>(Person.class, false);
this.grid.setItems(personList);
this.grid.setSelectionMode(SelectionMode.MULTI);
this.grid.setColumns("firstname");
this.grid.addComponentColumn(person -> {
// edit: added click listener for inline-editing of the person. Editor must be configured for this to work. See https://vaadin.com/components/vaadin-grid/java-examples/grid-editor
// You don't have to use inline-editing if you don't want. you can also edit the item in a separate Layout with Input fields and a Binder.
Button editButton = new Button(ImageIcons.EDIT.create(), click -> {
this.grid.getEditor().editItem(person);
});
editButton.getStyle().set("color", "#000000");
return editButton;
});
this.grid.addComponentColumn(person -> {
// edit: added click listener for person removal
Button deleteButton = new Button(null, IronIcons.DELETE_FOREVER.create(), click -> {
this.personDao.remove(person);
// TODO: when using an in-memory dataprovider, fetch all items again from service/dao and set them with grid.setItems(this.personDao.findAll());
// but that is not necessary when using a callback dataprovider, which I belive OP is using
this.grid.getDataProvider().refresh();
});
deleteButton.getStyle().set("color", "#000000");
return deleteButton;
}
this.addComponentAsFirst(this.grid);
Edit: a minor thing but I still wanted to mention it - You do some unnecessary creation of columns, only to remove them all again later. Instead of this you could tell the grid not to create these columns in the first place, by passing false as second parameter of the Grid constructor.
this.grid = new Grid(Person.class, false);
// instead of
this.grid = new Grid(Person.class);
this.grid.removeAllColumns();

How determine if a Vaadin table row clicked in has been selected or deselected?

Following a user clicking in a row in a Vaadin 7 table, how can I tell
if the row has been selected or deselected - clicking in a selected row deselects the row - (since there is also a column of
checkboxes which needs to kept in synch)?
When I tried table.getValue() in an ItemClickListener, this returned null if the
row is selected and the item id if the row is deselected - i.e. the opposite of
what I would have expected?
table.addItemClickListener(new ItemClickEvent.ItemClickListener() {
#Override
public void itemClick(ItemClickEvent event) {
// how tell if row has been selected or deselected?
Object idx = table.getValue();
}
});
Thank you,
Steve
In the Table api you can use the getValue() method, which results the selected rows.
Depending if in multiselct mode or not, you can then deduce what happens.
Use Vaadin Grid instead of table. It has the selectionListener property which will help you achieve what you need.
Grid API
(since there is also a column of checkboxes which needs to kept in
synch)?
Use Grid ans set grid.setSelectionMode(SelectionMode.MULTI); you will have one extra column with checkboxes by default.
Now, If you don't want to use Grid.
For Table you should use vaadinTable.addValueChangeListener(...) instead of ItemClickListener.
For Example :
table.addValueChangeListener(new ValueChangeListener() {
#Override
public void valueChange(ValueChangeEvent event) {
//Set checkbox object as an itemId
CheckBox itemId = (CheckBox)event.getProperty().getValue();
//Manage Collection to add selected items
if(table.isSelected(itemId)) {
table.select(itemId);
itemId.setValue(true);//Add this item to collection
} else {
table.unselect(itemId); //Remove this item to collection
itemId.setValue(false);
}
}
});
One another option is,
table.addItemClickListener(new ItemClickEvent.ItemClickListener() {
#Override
public void itemClick(ItemClickEvent event) {
//Manage collection and manually fetch property of table
Object value = event.getItem().getItemProperty("property").getValue();
}
});

could not be able to work with list control in flex 4.5

I want to be selected that new Item in list when I give new value to dataProvider but it selects the item that was firstly selected, and how to make that selected permanently on App start up.
You if want to select the list item after added to dataProvider. Probably you follow this
list.selectedIndex = list.dataProvider.length -1;
Sometimes if you added at desired position like
list.dataProvider.setItemAt(obj,2);
list.selectedIndex = 2
If you want to selected item permanently on App start up.(Make sure that your array collections bind-able to list)
public function onCreationComplete(event:FlexEvent):void
{
callLater(function():void
{
list.selectedIndex = list.dataProvider.length -1;
list.ensureIndexIsVisible(list.selectedIndex); // Viewport
});
}

Resources