diff --git a/pom.xml b/pom.xml
index 6758801..51abc71 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.flowingcode.vaadin.addons
twincolgrid
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
TwinColGrid add-on
Dual list component based on Vaadin Grids
https://www.flowingcode.com/en/open-source/
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGrid.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGrid.java
index abc1f87..c548c20 100644
--- a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGrid.java
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGrid.java
@@ -2,7 +2,7 @@
* #%L
* TwinColGrid add-on
* %%
- * Copyright (C) 2017 - 2022 Flowing Code
+ * Copyright (C) 2017 - 2025 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
import com.vaadin.flow.component.ComponentUtil;
import com.vaadin.flow.component.HasComponents;
import com.vaadin.flow.component.HasSize;
+import com.vaadin.flow.component.HasValidation;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.HasValue.ValueChangeEvent;
import com.vaadin.flow.component.HasValueAndElement;
@@ -79,7 +80,7 @@
@CssImport(value = "./styles/twin-col-grid-button.css")
@CssImport(value = "./styles/twincol-grid.css")
public class TwinColGrid extends VerticalLayout
- implements HasValueAndElement>, Set>, HasComponents, HasSize {
+ implements HasValueAndElement>, Set>, HasComponents, HasSize, HasValidation {
private static final class TwinColModel implements Serializable {
final Grid grid;
@@ -142,6 +143,8 @@ public enum Orientation {
private Span fakeButtonContainerLabel = new Span();
+ private Span errorMessageSpan = new Span();
+
private Orientation orientation = Orientation.HORIZONTAL;
private boolean autoResize = false;
@@ -184,7 +187,10 @@ public TwinColGrid(@NonNull Grid availableGrid, @NonNull Grid selectionGri
available = new TwinColModel<>(availableGrid, "twincol-grid-available");
selection = new TwinColModel<>(selectionGrid, "twincol-grid-selection");
-
+
+ errorMessageSpan.setClassName("twincol-grid-error-message");
+ selection.layout.addComponentAtIndex(1, errorMessageSpan);
+
setClassName("twincol-grid");
setMargin(false);
@@ -677,6 +683,26 @@ public boolean isRequiredIndicatorVisible() {
return getElement().getAttribute("required") != null;
}
+ @Override
+ public void setErrorMessage(String errorMessage) {
+ errorMessageSpan.setText(errorMessage);
+ }
+
+ @Override
+ public String getErrorMessage() {
+ return errorMessageSpan.getText();
+ }
+
+ @Override
+ public void setInvalid(boolean invalid) {
+ getElement().setAttribute("invalid", invalid);
+ }
+
+ @Override
+ public boolean isInvalid() {
+ return getElement().getAttribute("invalid") != null;
+ }
+
@Override
public void setReadOnly(final boolean readOnly) {
getAvailableGrid().setSelectionMode(readOnly ? SelectionMode.NONE : SelectionMode.MULTI);
@@ -956,4 +982,5 @@ private void updateOrientationOnResize(int width, int height) {
this.withOrientation(Orientation.HORIZONTAL);
}
}
+
}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGridListAdapter.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGridListAdapter.java
index bf06719..753ca3b 100644
--- a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGridListAdapter.java
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGridListAdapter.java
@@ -2,7 +2,7 @@
* #%L
* TwinColGrid add-on
* %%
- * Copyright (C) 2017 - 2022 Flowing Code
+ * Copyright (C) 2017 - 2025 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
*/
package com.flowingcode.vaadin.addons.twincolgrid;
+import com.vaadin.flow.component.HasValidation;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.HasValue.ValueChangeEvent;
import com.vaadin.flow.shared.Registration;
@@ -40,9 +41,9 @@
*/
@SuppressWarnings("serial")
@RequiredArgsConstructor
-class TwinColGridListAdapter implements HasValue>, List> {
+class TwinColGridListAdapter implements HasValue>, List>, HasValidation {
- private interface IDelegate {
+ private interface IDelegate extends HasValidation {
boolean isEmpty();
void clear();
diff --git a/src/main/resources/META-INF/resources/frontend/styles/twincol-grid.css b/src/main/resources/META-INF/resources/frontend/styles/twincol-grid.css
index f21c973..759babd 100644
--- a/src/main/resources/META-INF/resources/frontend/styles/twincol-grid.css
+++ b/src/main/resources/META-INF/resources/frontend/styles/twincol-grid.css
@@ -2,7 +2,7 @@
* #%L
* TwinColGrid add-on
* %%
- * Copyright (C) 2017 - 2022 Flowing Code
+ * Copyright (C) 2017 - 2025 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,6 +44,19 @@
color: var(--lumo-error-text-color);
}
+.twincol-grid .twincol-grid-selection .twincol-grid-error-message {
+ display: none;
+}
+
+.twincol-grid[invalid] .twincol-grid-selection .twincol-grid-error-message {
+ font-size: var(--vaadin-input-field-error-font-size, var(--lumo-font-size-xs));
+ line-height: var(--lumo-line-height-xs);
+ font-weight: var(--vaadin-input-field-error-font-weight, 400);
+ color: var(--vaadin-input-field-error-color, var(--lumo-error-text-color));
+ display: block;
+ padding-bottom: 4px;
+}
+
.twincol-grid .fake-button-container-label {
font-size: var(--lumo-font-size-s);
margin-bottom: calc(var(--vaadin-button-margin, var(--lumo-space-xs))* -1);
diff --git a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BoundDemo.java b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BoundDemo.java
index 56c99d1..113e41c 100644
--- a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BoundDemo.java
+++ b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BoundDemo.java
@@ -2,7 +2,7 @@
* #%L
* TwinColGrid add-on
* %%
- * Copyright (C) 2017 - 2022 Flowing Code
+ * Copyright (C) 2017 - 2025 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -58,7 +58,9 @@ public BoundDemo() {
twinColGrid.setCaption("TwinColGrid demo with Binder and row select without checkbox");
final Binder binder = new Binder<>();
- binder.forField(twinColGrid.asList()).asRequired().bind(Library::getBooks, Library::setBooks);
+ binder.forField(twinColGrid.asList())
+ .asRequired("You must add at least one book.")
+ .bind(Library::getBooks, Library::setBooks);
binder.setBean(library);
add(twinColGrid);