Skip to content

Commit f33ac0d

Browse files
mlopezFCpaodb
authored andcommitted
feat: add support for persistent checkbox multi selection
1 parent 2a202c1 commit f33ac0d

File tree

6 files changed

+142
-23
lines changed

6 files changed

+142
-23
lines changed

selection-grid-flow-demo/src/main/java/com/vaadin/componentfactory/selectiongrid/LazyDataView.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
package com.vaadin.componentfactory.selectiongrid;
22

3+
import java.util.stream.Stream;
4+
35
import com.vaadin.componentfactory.selectiongrid.bean.Person;
46
import com.vaadin.componentfactory.selectiongrid.service.PersonService;
7+
import com.vaadin.flow.component.checkbox.Checkbox;
58
import com.vaadin.flow.component.grid.Grid;
69
import com.vaadin.flow.component.html.Div;
10+
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
711
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
812
import com.vaadin.flow.data.provider.AbstractBackEndDataProvider;
913
import com.vaadin.flow.data.provider.Query;
1014
import com.vaadin.flow.router.Route;
1115

12-
import java.util.stream.Stream;
13-
1416
@Route(value = "lazy", layout = MainLayout.class)
1517
public class LazyDataView extends VerticalLayout
1618
{
@@ -22,9 +24,21 @@ public LazyDataView()
2224
{
2325
Div messageDiv = new Div();
2426

25-
Grid<Person> grid = new SelectionGrid<>();
27+
SelectionGrid<Person> grid = new SelectionGrid<>();
2628
grid.setDataProvider(personDataProvider);
27-
29+
Checkbox changeMultiselectionColumn = new Checkbox("Multiselection column");
30+
changeMultiselectionColumn.addValueChangeListener(event -> {
31+
grid.setMultiSelectionColumnVisible(event.getValue());
32+
});
33+
Checkbox persistentCheckboxSelection = new Checkbox("Persistent selection");
34+
persistentCheckboxSelection.setValue(true);
35+
persistentCheckboxSelection.addValueChangeListener(event -> {
36+
grid.setPersistentCheckboxSelection(event.getValue());
37+
});
38+
persistentCheckboxSelection.setTooltipText("When enabled, selecting a row via its checkbox will "
39+
+ "add or remove it from the current selection without clearing previously selected rows. "
40+
+ "This behavior allows users to manage selections manually using checkboxes, "
41+
+ "similar to how email clients like Gmail handle selection");
2842
grid.addColumn(Person::getFirstName).setHeader("First Name");
2943
grid.addColumn(Person::getAge).setHeader("Age");
3044

@@ -37,7 +51,7 @@ public LazyDataView()
3751
});
3852

3953
// You can pre-select items
40-
add(grid, messageDiv);
54+
add(new HorizontalLayout(changeMultiselectionColumn,persistentCheckboxSelection), grid, messageDiv);
4155
}
4256

4357
public static class PersonDataProvider extends AbstractBackEndDataProvider<Person, String> {

selection-grid-flow-demo/src/main/java/com/vaadin/componentfactory/selectiongrid/LazyFocusView.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public LazyFocusView()
3434
grid.focusOnCell(item.getValue(), personColumn);
3535
}
3636
});
37-
personComboBox.setDataProvider(personDataProvider,null);
37+
personComboBox.setItems(personDataProvider);
3838

3939
add(personComboBox);
4040
addAndExpand(grid);

selection-grid-flow-demo/src/main/java/com/vaadin/componentfactory/selectiongrid/SelectionTreeGridView.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.vaadin.flow.component.checkbox.Checkbox;
66
import com.vaadin.flow.component.grid.Grid;
77
import com.vaadin.flow.component.html.Div;
8+
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
89
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
910
import com.vaadin.flow.router.Route;
1011

@@ -21,8 +22,21 @@ public class SelectionTreeGridView extends VerticalLayout {
2122

2223
public SelectionTreeGridView() {
2324
SelectionTreeGrid<Department> grid = buildGrid();
25+
Checkbox changeMultiselectionColumn = new Checkbox("Multiselection column");
26+
changeMultiselectionColumn.addValueChangeListener(event -> {
27+
grid.setMultiSelectionColumnVisible(event.getValue());
28+
});
29+
Checkbox persistentCheckboxSelection = new Checkbox("Persistent selection");
30+
persistentCheckboxSelection.setValue(true);
31+
persistentCheckboxSelection.addValueChangeListener(event -> {
32+
grid.setPersistentCheckboxSelection(event.getValue());
33+
});
34+
persistentCheckboxSelection.setTooltipText("When enabled, selecting a row via its checkbox will "
35+
+ "add or remove it from the current selection without clearing previously selected rows. "
36+
+ "This behavior allows users to manage selections manually using checkboxes, "
37+
+ "similar to how email clients like Gmail handle selection");
2438
addAndExpand(grid);
25-
add(checkbox, messageDiv);
39+
add(new HorizontalLayout(checkbox, changeMultiselectionColumn, persistentCheckboxSelection), messageDiv);
2640
setPadding(false);
2741
setSizeFull();
2842
}

selection-grid-flow/src/main/java/com/vaadin/componentfactory/selectiongrid/SelectionGrid.java

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ public class SelectionGrid<T> extends Grid<T> {
4848

4949
private Integer selectRangeOnlyFromIndex = null;
5050
private Set<T> selectRangeOnlySelection = new HashSet<T>();
51+
private boolean multiSelectionColumnVisible = false;
52+
private boolean persistentCheckboxSelection = true;
5153

5254
/**
5355
* @see Grid#Grid()
@@ -90,7 +92,7 @@ public SelectionGrid(Class<T> beanType) {
9092
protected void onAttach(AttachEvent attachEvent) {
9193
super.onAttach(attachEvent);
9294
if (this.getSelectionModel() instanceof SelectionModel.Multi) {
93-
hideMultiSelectionColumn();
95+
setMultiSelectionColumnVisible(multiSelectionColumnVisible);
9496
}
9597
}
9698

@@ -294,7 +296,7 @@ private Optional<Stream<T>> fetchFromProvider(int offset, int limit) {
294296

295297
@Override
296298
protected void setSelectionModel(GridSelectionModel<T> model, SelectionMode selectionMode) {
297-
if (selectionMode == SelectionMode.MULTI) {
299+
if (selectionMode == SelectionMode.MULTI && !this.multiSelectionColumnVisible) {
298300
hideMultiSelectionColumn();
299301
}
300302
super.setSelectionModel(model, selectionMode);
@@ -305,11 +307,7 @@ protected void setSelectionModel(GridSelectionModel<T> model, SelectionMode sele
305307
* is not removed, but set to "hidden" explicitly.
306308
*/
307309
protected void hideMultiSelectionColumn() {
308-
getElement().getNode().runWhenAttached(ui ->
309-
ui.beforeClientResponse(this, context ->
310-
getElement().executeJs(
311-
"if (this.querySelector('vaadin-grid-flow-selection-column')) {" +
312-
" this.querySelector('vaadin-grid-flow-selection-column').hidden = true }")));
310+
this.setMultiSelectionColumnVisible(false);
313311
}
314312

315313
/**
@@ -331,4 +329,50 @@ public void removeThemeVariants(SelectionGridVariant... variants) {
331329
getThemeNames().removeAll(Stream.of(variants)
332330
.map(SelectionGridVariant::getVariantName).collect(Collectors.toList()));
333331
}
332+
333+
/**
334+
* Returns true if the multi selection column is visible, false otherwise.
335+
* @return
336+
*/
337+
public boolean isMultiSelectionColumnVisible() {
338+
return multiSelectionColumnVisible;
339+
}
340+
341+
/**
342+
* Sets the visibility of the multi selection column.
343+
*
344+
* @param multiSelectionColumnVisible - true to show the multi selection column, false to hide it
345+
*/
346+
public void setMultiSelectionColumnVisible(boolean multiSelectionColumnVisible) {
347+
if (this.getSelectionModel() instanceof SelectionModel.Multi) {
348+
getElement().getNode().runWhenAttached(ui ->
349+
ui.beforeClientResponse(this, context -> {
350+
getElement().executeJs(
351+
"if (this.querySelector('vaadin-grid-flow-selection-column')) {" +
352+
" this.querySelector('vaadin-grid-flow-selection-column').hidden = $0 }", !multiSelectionColumnVisible);
353+
this.recalculateColumnWidths();
354+
}));
355+
}
356+
this.multiSelectionColumnVisible = multiSelectionColumnVisible;
357+
}
358+
359+
/**
360+
* Returns true if the checkbox selection is persistent, false otherwise.
361+
*
362+
* @return
363+
*/
364+
public boolean isPersistentCheckboxSelection() {
365+
return persistentCheckboxSelection;
366+
}
367+
368+
/**
369+
* Sets the checkbox selection to be persistent or not.
370+
*
371+
* @param persistentCheckboxSelection - true to make the checkbox selection persistent, false otherwise
372+
*/
373+
public void setPersistentCheckboxSelection(boolean persistentCheckboxSelection) {
374+
this.getElement().executeJs("this.classicCheckboxSelection = $0", !persistentCheckboxSelection);
375+
this.persistentCheckboxSelection = persistentCheckboxSelection;
376+
}
377+
334378
}

selection-grid-flow/src/main/java/com/vaadin/componentfactory/selectiongrid/SelectionTreeGrid.java

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,16 @@
4747
*
4848
* @param <T> – the grid bean type
4949
*/
50+
@SuppressWarnings("serial")
5051
@Tag("vaadin-selection-grid")
5152
@CssImport(value = "./styles/grid.css", themeFor = "vaadin-selection-grid")
5253
@JsModule("./src/vcf-selection-grid.js")
5354
@JsModule("./src/selection-grid.js")
5455
public class SelectionTreeGrid<T> extends TreeGrid<T> {
5556

57+
private boolean multiSelectionColumnVisible = false;
58+
private boolean persistentCheckboxSelection = true;
59+
5660
/**
5761
* @see TreeGrid#TreeGrid()
5862
*/
@@ -90,7 +94,7 @@ public SelectionTreeGrid(HierarchicalDataProvider<T, ?> dataProvider) {
9094
protected void onAttach(AttachEvent attachEvent) {
9195
super.onAttach(attachEvent);
9296
if (this.getSelectionModel() instanceof SelectionModel.Multi) {
93-
hideMultiSelectionColumn();
97+
setMultiSelectionColumnVisible(multiSelectionColumnVisible);
9498
}
9599
}
96100

@@ -221,7 +225,7 @@ private void selectRangeOnlyOnClick(int fromIndex, int toIndex) {
221225
@Override
222226
protected void setSelectionModel(GridSelectionModel<T> model, SelectionMode selectionMode) {
223227
if (selectionMode == SelectionMode.MULTI) {
224-
hideMultiSelectionColumn();
228+
setMultiSelectionColumnVisible(multiSelectionColumnVisible);
225229
}
226230
super.setSelectionModel(model, selectionMode);
227231
}
@@ -231,14 +235,9 @@ protected void setSelectionModel(GridSelectionModel<T> model, SelectionMode sele
231235
* is not removed, but set to "hidden" explicitly.
232236
*/
233237
protected void hideMultiSelectionColumn() {
234-
getElement().getNode().runWhenAttached(ui ->
235-
ui.beforeClientResponse(this, context ->
236-
getElement().executeJs(
237-
"if (this.querySelector('vaadin-grid-flow-selection-column')) {" +
238-
" this.querySelector('vaadin-grid-flow-selection-column').hidden = true }")));
238+
this.setMultiSelectionColumnVisible(false);
239239
}
240240

241-
242241
@Override
243242
public Column<T> addHierarchyColumn(ValueProvider<T, ?> valueProvider) {
244243
Column<T> column = addColumn(LitRenderer.<T> of(
@@ -284,4 +283,49 @@ public void removeThemeVariants(SelectionGridVariant... variants) {
284283
getThemeNames().removeAll(Stream.of(variants)
285284
.map(SelectionGridVariant::getVariantName).collect(Collectors.toList()));
286285
}
286+
287+
/**
288+
* Returns true if the multi selection column is visible, false otherwise.
289+
* @return
290+
*/
291+
public boolean isMultiSelectionColumnVisible() {
292+
return multiSelectionColumnVisible;
293+
}
294+
295+
/**
296+
* Sets the visibility of the multi selection column.
297+
*
298+
* @param multiSelectionColumnVisible - true to show the multi selection column, false to hide it
299+
*/
300+
public void setMultiSelectionColumnVisible(boolean multiSelectionColumnVisible) {
301+
if (this.getSelectionModel() instanceof SelectionModel.Multi) {
302+
getElement().getNode().runWhenAttached(ui ->
303+
ui.beforeClientResponse(this, context -> {
304+
getElement().executeJs(
305+
"if (this.querySelector('vaadin-grid-flow-selection-column')) {" +
306+
" this.querySelector('vaadin-grid-flow-selection-column').hidden = $0 }", !multiSelectionColumnVisible);
307+
this.recalculateColumnWidths();
308+
}));
309+
}
310+
this.multiSelectionColumnVisible = multiSelectionColumnVisible;
311+
}
312+
313+
/**
314+
* Returns true if the checkbox selection is persistent, false otherwise.
315+
*
316+
* @return
317+
*/
318+
public boolean isPersistentCheckboxSelection() {
319+
return persistentCheckboxSelection;
320+
}
321+
322+
/**
323+
* Sets the checkbox selection to be persistent or not.
324+
*
325+
* @param persistentCheckboxSelection - true to make the checkbox selection persistent, false otherwise
326+
*/
327+
public void setPersistentCheckboxSelection(boolean persistentCheckboxSelection) {
328+
this.getElement().executeJs("this.classicCheckboxSelection = $0", !persistentCheckboxSelection);
329+
this.persistentCheckboxSelection = persistentCheckboxSelection;
330+
}
287331
}

selection-grid-flow/src/main/resources/META-INF/resources/frontend/src/helpers.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ export function _debounce(func, wait, immediate) {
5050
}
5151
};
5252
export function _selectionGridSelectRowWithItem(e, item, index) {
53-
const ctrlKey = (e.metaKey)?e.metaKey:e.ctrlKey; //(this._ios)?e.metaKey:e.ctrlKey;
53+
let ctrlKey = (e.metaKey)?e.metaKey:e.ctrlKey; //(this._ios)?e.metaKey:e.ctrlKey;
54+
if (!this.classicCheckboxSelection && e.srcElement && e.srcElement.parentNode && e.srcElement.parentNode.nodeName === 'VAADIN-CHECKBOX') {
55+
ctrlKey = true;
56+
}
5457
// if click select only this row
5558
if (!ctrlKey && !e.shiftKey) {
5659
if (this.$server) {

0 commit comments

Comments
 (0)