Merge pull request #16134 from marcushellberg/master
Updates for vaadin intro article
This commit is contained in:
commit
b5bfa4697d
|
@ -0,0 +1 @@
|
||||||
|
frontend/generated
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
This file is auto-generated by Vaadin.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<style>
|
||||||
|
body, #outlet {
|
||||||
|
height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!-- index.ts is included here automatically (either by the dev server or during the build) -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- This outlet div is where the views are rendered -->
|
||||||
|
<div id="outlet"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
180
vaadin/pom.xml
180
vaadin/pom.xml
|
@ -1,13 +1,12 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.test</groupId>
|
<groupId>org.test</groupId>
|
||||||
<artifactId>vaadin</artifactId>
|
<artifactId>vaadin</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
<name>vaadin</name>
|
<name>vaadin</name>
|
||||||
<packaging>war</packaging>
|
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baeldung</groupId>
|
<groupId>com.baeldung</groupId>
|
||||||
|
@ -16,6 +15,11 @@
|
||||||
<relativePath>../parent-boot-3</relativePath>
|
<relativePath>../parent-boot-3</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
|
<vaadin.version>24.3.3</vaadin.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -30,39 +34,24 @@
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.servlet</groupId>
|
<groupId>com.vaadin</groupId>
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
<artifactId>vaadin-core</artifactId>
|
||||||
<version>4.0.1</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.vaadin</groupId>
|
<groupId>com.vaadin</groupId>
|
||||||
<artifactId>vaadin-server</artifactId>
|
<artifactId>vaadin-spring-boot-starter</artifactId>
|
||||||
<version>${vaadin-server.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.vaadin</groupId>
|
|
||||||
<artifactId>vaadin-push</artifactId>
|
|
||||||
<version>${vaadin-push.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.vaadin</groupId>
|
|
||||||
<artifactId>vaadin-client-compiled</artifactId>
|
|
||||||
<version>${vaadin-client-compiled.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.vaadin</groupId>
|
|
||||||
<artifactId>vaadin-themes</artifactId>
|
|
||||||
<version>${vaadin-themes.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.vaadin</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>vaadin-spring-boot-starter</artifactId>
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
<version>${vaadin-spring-boot-starter.version}</version>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.projectreactor</groupId>
|
||||||
|
<artifactId>reactor-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
@ -77,47 +66,17 @@
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-war-plugin</artifactId>
|
|
||||||
<version>${maven-war-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
|
||||||
<!-- Exclude an unnecessary file generated by the GWT compiler. -->
|
|
||||||
<packagingExcludes>WEB-INF/classes/VAADIN/widgetsets/WEB-INF/**</packagingExcludes>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>com.vaadin</groupId>
|
<groupId>com.vaadin</groupId>
|
||||||
<artifactId>vaadin-maven-plugin</artifactId>
|
<artifactId>vaadin-maven-plugin</artifactId>
|
||||||
<version>${vaadin.plugin.version}</version>
|
<version>${vaadin.version}</version>
|
||||||
</plugin>
|
<executions>
|
||||||
<plugin>
|
<execution>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<goals>
|
||||||
<artifactId>maven-clean-plugin</artifactId>
|
<goal>prepare-frontend</goal>
|
||||||
<version>${maven-clean-plugin.version}</version>
|
</goals>
|
||||||
<!-- Clean up also any pre-compiled themes -->
|
</execution>
|
||||||
<configuration>
|
</executions>
|
||||||
<filesets>
|
|
||||||
<fileset>
|
|
||||||
<directory>src/main/webapp/VAADIN/themes</directory>
|
|
||||||
<includes>
|
|
||||||
<include>**/styles.css</include>
|
|
||||||
<include>**/styles.scss.cache</include>
|
|
||||||
</includes>
|
|
||||||
</fileset>
|
|
||||||
</filesets>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<!-- The Jetty plugin allows us to easily test the development build by running jetty:run -->
|
|
||||||
<!-- on the command line. -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-maven-plugin</artifactId>
|
|
||||||
<version>${jetty.plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<scanIntervalSeconds>2</scanIntervalSeconds>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
@ -126,68 +85,41 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>vaadin-addons</id>
|
|
||||||
<url>https://maven.vaadin.com/vaadin-addons</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
<profile>
|
<profile>
|
||||||
<!-- Vaadin pre-release repositories -->
|
<!-- Production mode is activated using -Pproduction -->
|
||||||
<id>vaadin-prerelease</id>
|
<id>production</id>
|
||||||
<activation>
|
<dependencies>
|
||||||
<activeByDefault>false</activeByDefault>
|
<!-- Exclude development dependencies from production -->
|
||||||
</activation>
|
<dependency>
|
||||||
|
<groupId>com.vaadin</groupId>
|
||||||
<repositories>
|
<artifactId>vaadin-core</artifactId>
|
||||||
<repository>
|
<exclusions>
|
||||||
<id>vaadin-prereleases</id>
|
<exclusion>
|
||||||
<url>https://maven.vaadin.com/vaadin-prereleases</url>
|
<groupId>com.vaadin</groupId>
|
||||||
</repository>
|
<artifactId>vaadin-dev</artifactId>
|
||||||
<repository>
|
</exclusion>
|
||||||
<id>vaadin-snapshots</id>
|
</exclusions>
|
||||||
<url>https://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
|
</dependency>
|
||||||
<releases>
|
</dependencies>
|
||||||
<enabled>false</enabled>
|
<build>
|
||||||
</releases>
|
<plugins>
|
||||||
<snapshots>
|
<plugin>
|
||||||
<enabled>true</enabled>
|
<groupId>com.vaadin</groupId>
|
||||||
</snapshots>
|
<artifactId>vaadin-maven-plugin</artifactId>
|
||||||
</repository>
|
<version>${vaadin.version}</version>
|
||||||
</repositories>
|
<executions>
|
||||||
<pluginRepositories>
|
<execution>
|
||||||
<pluginRepository>
|
<goals>
|
||||||
<id>vaadin-prereleases</id>
|
<goal>build-frontend</goal>
|
||||||
<url>https://maven.vaadin.com/vaadin-prereleases</url>
|
</goals>
|
||||||
</pluginRepository>
|
<phase>compile</phase>
|
||||||
<pluginRepository>
|
</execution>
|
||||||
<id>vaadin-snapshots</id>
|
</executions>
|
||||||
<url>https://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
|
</plugin>
|
||||||
<releases>
|
</plugins>
|
||||||
<enabled>false</enabled>
|
</build>
|
||||||
</releases>
|
|
||||||
<snapshots>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
</snapshots>
|
|
||||||
</pluginRepository>
|
|
||||||
</pluginRepositories>
|
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<vaadin.version>13.0.9</vaadin.version>
|
|
||||||
<vaadin.plugin.version>13.0.9</vaadin.plugin.version>
|
|
||||||
<vaadin-spring-boot-starter.version>13.0.9</vaadin-spring-boot-starter.version>
|
|
||||||
<vaadin-server.version>8.8.5</vaadin-server.version>
|
|
||||||
<vaadin-push.version>8.8.5</vaadin-push.version>
|
|
||||||
<vaadin-client-compiled.version>8.8.5</vaadin-client-compiled.version>
|
|
||||||
<vaadin-themes.version>8.8.5</vaadin-themes.version>
|
|
||||||
<jetty.plugin.version>9.3.9.v20160517</jetty.plugin.version>
|
|
||||||
<vaadin.widgetset.mode>local</vaadin.widgetset.mode>
|
|
||||||
<vaadin.theme>mytheme</vaadin.theme>
|
|
||||||
<maven-clean-plugin.version>3.0.0</maven-clean-plugin.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -1,15 +1,19 @@
|
||||||
package com.baeldung;
|
package com.baeldung;
|
||||||
|
|
||||||
|
import com.baeldung.data.Employee;
|
||||||
|
import com.baeldung.data.EmployeeRepository;
|
||||||
|
import com.vaadin.flow.component.page.AppShellConfigurator;
|
||||||
|
import com.vaadin.flow.component.page.Push;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.springframework.boot.CommandLineRunner;
|
import org.springframework.boot.CommandLineRunner;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
@Push
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class Application {
|
public class Application implements AppShellConfigurator {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(Application.class);
|
private static final Logger log = LoggerFactory.getLogger(Application.class);
|
||||||
|
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
package com.baeldung;
|
|
||||||
|
|
||||||
import com.vaadin.flow.component.Key;
|
|
||||||
import com.vaadin.flow.component.KeyNotifier;
|
|
||||||
import com.vaadin.flow.component.button.Button;
|
|
||||||
import com.vaadin.flow.component.icon.VaadinIcon;
|
|
||||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
|
||||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
|
||||||
import com.vaadin.flow.component.textfield.TextField;
|
|
||||||
import com.vaadin.flow.data.binder.Binder;
|
|
||||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
|
||||||
import com.vaadin.flow.spring.annotation.UIScope;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
@SpringComponent
|
|
||||||
@UIScope
|
|
||||||
public class EmployeeEditor extends VerticalLayout implements KeyNotifier {
|
|
||||||
|
|
||||||
private final EmployeeRepository repository;
|
|
||||||
|
|
||||||
private Employee employee;
|
|
||||||
|
|
||||||
TextField firstName = new TextField("First name");
|
|
||||||
TextField lastName = new TextField("Last name");
|
|
||||||
|
|
||||||
Button save = new Button("Save", VaadinIcon.CHECK.create());
|
|
||||||
Button cancel = new Button("Cancel");
|
|
||||||
Button delete = new Button("Delete", VaadinIcon.TRASH.create());
|
|
||||||
HorizontalLayout actions = new HorizontalLayout(save, cancel, delete);
|
|
||||||
|
|
||||||
Binder<Employee> binder = new Binder<>(Employee.class);
|
|
||||||
private ChangeHandler changeHandler;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public EmployeeEditor(EmployeeRepository repository) {
|
|
||||||
this.repository = repository;
|
|
||||||
|
|
||||||
add(firstName, lastName, actions);
|
|
||||||
|
|
||||||
binder.bindInstanceFields(this);
|
|
||||||
|
|
||||||
setSpacing(true);
|
|
||||||
|
|
||||||
save.getElement().getThemeList().add("primary");
|
|
||||||
delete.getElement().getThemeList().add("error");
|
|
||||||
|
|
||||||
addKeyPressListener(Key.ENTER, e -> save());
|
|
||||||
|
|
||||||
save.addClickListener(e -> save());
|
|
||||||
delete.addClickListener(e -> delete());
|
|
||||||
cancel.addClickListener(e -> editEmployee(employee));
|
|
||||||
setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete() {
|
|
||||||
repository.delete(employee);
|
|
||||||
changeHandler.onChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
void save() {
|
|
||||||
repository.save(employee);
|
|
||||||
changeHandler.onChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ChangeHandler {
|
|
||||||
void onChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void editEmployee(Employee c) {
|
|
||||||
if (c == null) {
|
|
||||||
setVisible(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final boolean persisted = c.getId() != null;
|
|
||||||
if (persisted) {
|
|
||||||
employee = repository.findById(c.getId()).get();
|
|
||||||
} else {
|
|
||||||
employee = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel.setVisible(persisted);
|
|
||||||
binder.setBean(employee);
|
|
||||||
setVisible(true);
|
|
||||||
firstName.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setChangeHandler(ChangeHandler h) {
|
|
||||||
changeHandler = h;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.baeldung;
|
||||||
|
|
||||||
|
import com.baeldung.introduction.PushView;
|
||||||
|
import com.baeldung.introduction.basics.VaadinFlowBasics;
|
||||||
|
import com.baeldung.introduction.FormView;
|
||||||
|
import com.baeldung.introduction.GridView;
|
||||||
|
import com.baeldung.spring.EmployeesView;
|
||||||
|
import com.vaadin.flow.component.html.H1;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
import com.vaadin.flow.router.RouterLink;
|
||||||
|
|
||||||
|
@Route("")
|
||||||
|
public class IndexView extends VerticalLayout {
|
||||||
|
|
||||||
|
public IndexView() {
|
||||||
|
add(new H1("Vaadin Flow examples"));
|
||||||
|
|
||||||
|
add(new RouterLink("Basics", VaadinFlowBasics.class));
|
||||||
|
add(new RouterLink("Grid", GridView.class));
|
||||||
|
add(new RouterLink("Form", FormView.class));
|
||||||
|
add(new RouterLink("Push", PushView.class));
|
||||||
|
add(new RouterLink("CRUD", EmployeesView.class));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,67 +0,0 @@
|
||||||
package com.baeldung;
|
|
||||||
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import com.vaadin.flow.component.button.Button;
|
|
||||||
import com.vaadin.flow.component.grid.Grid;
|
|
||||||
import com.vaadin.flow.component.icon.VaadinIcon;
|
|
||||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
|
||||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
|
||||||
import com.vaadin.flow.component.textfield.TextField;
|
|
||||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
|
||||||
import com.vaadin.flow.router.Route;
|
|
||||||
|
|
||||||
@Route
|
|
||||||
public class MainView extends VerticalLayout {
|
|
||||||
|
|
||||||
private final EmployeeRepository employeeRepository;
|
|
||||||
|
|
||||||
private final EmployeeEditor editor;
|
|
||||||
|
|
||||||
final Grid<Employee> grid;
|
|
||||||
|
|
||||||
final TextField filter;
|
|
||||||
|
|
||||||
private final Button addNewBtn;
|
|
||||||
|
|
||||||
public MainView(EmployeeRepository repo, EmployeeEditor editor) {
|
|
||||||
this.employeeRepository = repo;
|
|
||||||
this.editor = editor;
|
|
||||||
this.grid = new Grid<>(Employee.class);
|
|
||||||
this.filter = new TextField();
|
|
||||||
this.addNewBtn = new Button("New employee", VaadinIcon.PLUS.create());
|
|
||||||
|
|
||||||
HorizontalLayout actions = new HorizontalLayout(filter, addNewBtn);
|
|
||||||
add(actions, grid, editor);
|
|
||||||
|
|
||||||
grid.setHeight("200px");
|
|
||||||
grid.setColumns("id", "firstName", "lastName");
|
|
||||||
grid.getColumnByKey("id").setWidth("50px").setFlexGrow(0);
|
|
||||||
|
|
||||||
filter.setPlaceholder("Filter by last name");
|
|
||||||
|
|
||||||
filter.setValueChangeMode(ValueChangeMode.EAGER);
|
|
||||||
filter.addValueChangeListener(e -> listEmployees(e.getValue()));
|
|
||||||
|
|
||||||
grid.asSingleSelect().addValueChangeListener(e -> {
|
|
||||||
editor.editEmployee(e.getValue());
|
|
||||||
});
|
|
||||||
|
|
||||||
addNewBtn.addClickListener(e -> editor.editEmployee(new Employee("", "")));
|
|
||||||
|
|
||||||
editor.setChangeHandler(() -> {
|
|
||||||
editor.setVisible(false);
|
|
||||||
listEmployees(filter.getValue());
|
|
||||||
});
|
|
||||||
|
|
||||||
listEmployees(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
void listEmployees(String filterText) {
|
|
||||||
if (StringUtils.isEmpty(filterText)) {
|
|
||||||
grid.setItems(employeeRepository.findAll());
|
|
||||||
} else {
|
|
||||||
grid.setItems(employeeRepository.findByLastNameStartsWithIgnoreCase(filterText));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.baeldung.data;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.validation.constraints.Email;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Contact {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
@NotBlank
|
||||||
|
private String name;
|
||||||
|
@Email
|
||||||
|
private String email;
|
||||||
|
@Pattern(regexp = "\\d{3}-\\d{3}-\\d{4}")
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
public Contact() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Contact(String name, String email, String phone) {
|
||||||
|
this.name = name;
|
||||||
|
this.email = email;
|
||||||
|
this.phone = phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPhone() {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhone(String phone) {
|
||||||
|
this.phone = phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Contact {" +
|
||||||
|
"id=" + id +
|
||||||
|
", name='" + name + "'" +
|
||||||
|
", email='" + email + "'" +
|
||||||
|
", phone='" + phone + "'" +
|
||||||
|
" }";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.baeldung.data;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface ContactRepository extends JpaRepository<Contact, Long> {
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.baeldung.data;
|
||||||
|
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class DataInitializer implements CommandLineRunner {
|
||||||
|
|
||||||
|
private final ContactRepository contactRepository;
|
||||||
|
|
||||||
|
public DataInitializer(ContactRepository contactRepository) {
|
||||||
|
this.contactRepository = contactRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<String> firstNames = List.of(
|
||||||
|
"John", "Jane", "Emily", "Michael", "Sarah", "James", "Mary", "Robert",
|
||||||
|
"Patricia", "William", "Linda", "David", "Barbara", "Richard", "Susan",
|
||||||
|
"Joseph", "Jessica", "Thomas", "Karen", "Charles"
|
||||||
|
);
|
||||||
|
private final List<String> lastNames = List.of(
|
||||||
|
"Doe", "Smith", "Johnson", "Brown", "Davis", "Miller", "Wilson", "Moore",
|
||||||
|
"Taylor", "Anderson", "Thomas", "Jackson", "White", "Harris", "Martin",
|
||||||
|
"Thompson", "Garcia", "Martinez", "Robinson", "Clark"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(String... args) throws Exception {
|
||||||
|
var contacts = new ArrayList<Contact>();
|
||||||
|
Random random = new Random();
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
String firstName = firstNames.get(random.nextInt(firstNames.size()));
|
||||||
|
String lastName = lastNames.get(random.nextInt(lastNames.size()));
|
||||||
|
String email = String.format("%s.%s@example.com", firstName.toLowerCase(), lastName.toLowerCase());
|
||||||
|
String phone = String.format("555-%03d-%04d", random.nextInt(1000), random.nextInt(10000));
|
||||||
|
|
||||||
|
contacts.add(new Contact(firstName + " " + lastName, email, phone));
|
||||||
|
}
|
||||||
|
|
||||||
|
contactRepository.saveAll(contacts);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
package com.baeldung;
|
package com.baeldung.data;
|
||||||
|
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class Employee {
|
public class Employee {
|
||||||
|
@ -11,11 +13,13 @@ public class Employee {
|
||||||
@GeneratedValue
|
@GeneratedValue
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
@Size(min = 2, message = "First name must have at least 2 characters")
|
||||||
private String firstName;
|
private String firstName;
|
||||||
|
|
||||||
|
@Size(min = 2, message = "Last name must have at least 2 characters")
|
||||||
private String lastName;
|
private String lastName;
|
||||||
|
|
||||||
protected Employee() {
|
public Employee() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Employee(String firstName, String lastName) {
|
public Employee(String firstName, String lastName) {
|
||||||
|
@ -27,6 +31,10 @@ public class Employee {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
public String getFirstName() {
|
public String getFirstName() {
|
||||||
return firstName;
|
return firstName;
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.baeldung;
|
package com.baeldung.data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
package com.baeldung.introduction;
|
|
||||||
|
|
||||||
public class BindData {
|
|
||||||
|
|
||||||
private String bindName;
|
|
||||||
|
|
||||||
public BindData(String bindName){
|
|
||||||
this.bindName = bindName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getBindName() {
|
|
||||||
return bindName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBindName(String bindName) {
|
|
||||||
this.bindName = bindName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
package com.baeldung.introduction;
|
||||||
|
|
||||||
|
import com.baeldung.data.Contact;
|
||||||
|
import com.vaadin.flow.component.button.Button;
|
||||||
|
import com.vaadin.flow.component.html.H2;
|
||||||
|
import com.vaadin.flow.component.notification.Notification;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.component.textfield.TextField;
|
||||||
|
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||||
|
import com.vaadin.flow.data.binder.Binder;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
|
||||||
|
@Route("form")
|
||||||
|
public class FormView extends HorizontalLayout {
|
||||||
|
|
||||||
|
public FormView() {
|
||||||
|
addBeanValidationExample();
|
||||||
|
addCustomValidationExample();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addBeanValidationExample() {
|
||||||
|
var nameField = new TextField("Name");
|
||||||
|
var emailField = new TextField("Email");
|
||||||
|
var phoneField = new TextField("Phone");
|
||||||
|
var saveButton = new Button("Save");
|
||||||
|
|
||||||
|
var binder = new BeanValidationBinder<>(Contact.class);
|
||||||
|
|
||||||
|
binder.forField(nameField).bind(Contact::getName, Contact::setName);
|
||||||
|
binder.forField(emailField).bind(Contact::getEmail, Contact::setEmail);
|
||||||
|
binder.forField(phoneField).bind(Contact::getPhone, Contact::setPhone);
|
||||||
|
|
||||||
|
var contact = new Contact("John Doe", "john@doe.com", "123-456-7890");
|
||||||
|
binder.setBean(contact);
|
||||||
|
|
||||||
|
saveButton.addClickListener(e -> {
|
||||||
|
if (binder.validate().isOk()) {
|
||||||
|
Notification.show("Saved " + contact);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add(new VerticalLayout(
|
||||||
|
new H2("Bean Validation Example"),
|
||||||
|
nameField,
|
||||||
|
emailField,
|
||||||
|
phoneField,
|
||||||
|
saveButton
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCustomValidationExample() {
|
||||||
|
|
||||||
|
var nameField = new TextField("Name");
|
||||||
|
var emailField = new TextField("Email");
|
||||||
|
var phoneField = new TextField("Phone");
|
||||||
|
var saveButton = new Button("Save");
|
||||||
|
|
||||||
|
var binder = new Binder<>(Contact.class);
|
||||||
|
|
||||||
|
binder.forField(nameField)
|
||||||
|
.asRequired()
|
||||||
|
.bind(Contact::getName, Contact::setName);
|
||||||
|
binder.forField(emailField)
|
||||||
|
.withValidator(email -> email.contains("@"), "Not a valid email address")
|
||||||
|
.bind(Contact::getEmail, Contact::setEmail);
|
||||||
|
binder.forField(phoneField)
|
||||||
|
.withValidator(phone -> phone.matches("\\d{3}-\\d{3}-\\d{4}"), "Not a valid phone number")
|
||||||
|
.bind(Contact::getPhone, Contact::setPhone);
|
||||||
|
|
||||||
|
var contact = new Contact("John Doe", "john@doe.com", "123-456-7890");
|
||||||
|
binder.setBean(contact);
|
||||||
|
|
||||||
|
saveButton.addClickListener(e -> {
|
||||||
|
if (binder.validate().isOk()) {
|
||||||
|
Notification.show("Saved " + contact);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add(new VerticalLayout(
|
||||||
|
new H2("Custom Validation Example"),
|
||||||
|
nameField,
|
||||||
|
emailField,
|
||||||
|
phoneField,
|
||||||
|
saveButton
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.baeldung.introduction;
|
||||||
|
|
||||||
|
import com.baeldung.data.Contact;
|
||||||
|
import com.baeldung.data.ContactRepository;
|
||||||
|
import com.vaadin.flow.component.grid.Grid;
|
||||||
|
import com.vaadin.flow.component.html.H1;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
import com.vaadin.flow.spring.data.VaadinSpringDataHelpers;
|
||||||
|
|
||||||
|
@Route("grid")
|
||||||
|
public class GridView extends VerticalLayout {
|
||||||
|
|
||||||
|
public GridView(ContactRepository contactRepository) {
|
||||||
|
|
||||||
|
add(new H1("Using data grids"));
|
||||||
|
|
||||||
|
// Define a grid for a Contact entity
|
||||||
|
var grid = new Grid<Contact>();
|
||||||
|
grid.addColumn(Contact::getName).setHeader("Name");
|
||||||
|
grid.addColumn(Contact::getEmail).setHeader("Email");
|
||||||
|
grid.addColumn(Contact::getPhone).setHeader("Phone");
|
||||||
|
|
||||||
|
// There are two ways to populate the grid with data:
|
||||||
|
|
||||||
|
// 1) In-memory with a list of items
|
||||||
|
var contacts = contactRepository.findAll();
|
||||||
|
grid.setItems(contacts);
|
||||||
|
|
||||||
|
// 2) with a callback to lazily load items from a data source.
|
||||||
|
grid.setItems(query -> {
|
||||||
|
// Turn the page, offset, filter, sort and other info in query into a Spring Data PageRequest
|
||||||
|
var pageRequest = VaadinSpringDataHelpers.toSpringPageRequest(query);
|
||||||
|
return contactRepository.findAll(pageRequest).stream();
|
||||||
|
});
|
||||||
|
|
||||||
|
add(grid);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.baeldung.introduction;
|
||||||
|
|
||||||
|
import com.vaadin.flow.component.html.Span;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
// Ensure you have @Push annotation in your Application class
|
||||||
|
@Route("push")
|
||||||
|
public class PushView extends VerticalLayout {
|
||||||
|
|
||||||
|
public PushView() {
|
||||||
|
var output = new Span();
|
||||||
|
|
||||||
|
// Publish server time once a second
|
||||||
|
var serverTime = Flux.interval(Duration.ofSeconds(1))
|
||||||
|
.map(o -> "Server time: " + Instant.now());
|
||||||
|
|
||||||
|
|
||||||
|
serverTime.subscribe(time ->
|
||||||
|
// ui.access is required to update the UI from a background thread
|
||||||
|
getUI().ifPresent(ui ->
|
||||||
|
ui.access(() -> output.setText(time))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
add(output);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,45 +0,0 @@
|
||||||
package com.baeldung.introduction;
|
|
||||||
|
|
||||||
public class Row {
|
|
||||||
|
|
||||||
private String column1;
|
|
||||||
|
|
||||||
private String column2;
|
|
||||||
|
|
||||||
private String column3;
|
|
||||||
|
|
||||||
public Row() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Row(String column1, String column2, String column3) {
|
|
||||||
super();
|
|
||||||
this.column1 = column1;
|
|
||||||
this.column2 = column2;
|
|
||||||
this.column3 = column3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getColumn1() {
|
|
||||||
return column1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setColumn1(String column1) {
|
|
||||||
this.column1 = column1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getColumn2() {
|
|
||||||
return column2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setColumn2(String column2) {
|
|
||||||
this.column2 = column2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getColumn3() {
|
|
||||||
return column3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setColumn3(String column3) {
|
|
||||||
this.column3 = column3;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,281 +0,0 @@
|
||||||
package com.baeldung.introduction;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import com.vaadin.annotations.Push;
|
|
||||||
import com.vaadin.annotations.Theme;
|
|
||||||
import com.vaadin.annotations.VaadinServletConfiguration;
|
|
||||||
import com.vaadin.data.Binder;
|
|
||||||
import com.vaadin.data.validator.StringLengthValidator;
|
|
||||||
import com.vaadin.icons.VaadinIcons;
|
|
||||||
import com.vaadin.server.ExternalResource;
|
|
||||||
import com.vaadin.server.VaadinRequest;
|
|
||||||
import com.vaadin.server.VaadinServlet;
|
|
||||||
import com.vaadin.ui.Button;
|
|
||||||
import com.vaadin.ui.CheckBox;
|
|
||||||
import com.vaadin.ui.ComboBox;
|
|
||||||
import com.vaadin.ui.DateField;
|
|
||||||
import com.vaadin.ui.FormLayout;
|
|
||||||
import com.vaadin.ui.Grid;
|
|
||||||
import com.vaadin.ui.GridLayout;
|
|
||||||
import com.vaadin.ui.HorizontalLayout;
|
|
||||||
import com.vaadin.ui.InlineDateField;
|
|
||||||
import com.vaadin.ui.Label;
|
|
||||||
import com.vaadin.ui.Link;
|
|
||||||
import com.vaadin.ui.ListSelect;
|
|
||||||
import com.vaadin.ui.NativeButton;
|
|
||||||
import com.vaadin.ui.NativeSelect;
|
|
||||||
import com.vaadin.ui.Panel;
|
|
||||||
import com.vaadin.ui.PasswordField;
|
|
||||||
import com.vaadin.ui.RichTextArea;
|
|
||||||
import com.vaadin.ui.TextArea;
|
|
||||||
import com.vaadin.ui.TextField;
|
|
||||||
import com.vaadin.ui.TwinColSelect;
|
|
||||||
import com.vaadin.ui.UI;
|
|
||||||
import com.vaadin.ui.VerticalLayout;
|
|
||||||
import jakarta.servlet.annotation.WebServlet;
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
@Push
|
|
||||||
@Theme("mytheme")
|
|
||||||
public class VaadinUI extends UI {
|
|
||||||
|
|
||||||
private Label currentTime;
|
|
||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
|
||||||
@Override
|
|
||||||
protected void init(VaadinRequest vaadinRequest) {
|
|
||||||
final VerticalLayout verticalLayout = new VerticalLayout();
|
|
||||||
verticalLayout.setSpacing(true);
|
|
||||||
verticalLayout.setMargin(true);
|
|
||||||
final GridLayout gridLayout = new GridLayout(3, 2);
|
|
||||||
gridLayout.setSpacing(true);
|
|
||||||
gridLayout.setMargin(true);
|
|
||||||
final HorizontalLayout horizontalLayout = new HorizontalLayout();
|
|
||||||
horizontalLayout.setSpacing(true);
|
|
||||||
horizontalLayout.setMargin(true);
|
|
||||||
final FormLayout formLayout = new FormLayout();
|
|
||||||
formLayout.setSpacing(true);
|
|
||||||
formLayout.setMargin(true);
|
|
||||||
final GridLayout buttonLayout = new GridLayout(3, 5);
|
|
||||||
buttonLayout.setMargin(true);
|
|
||||||
buttonLayout.setSpacing(true);
|
|
||||||
|
|
||||||
final Label label = new Label();
|
|
||||||
label.setId("Label");
|
|
||||||
label.setValue("Label Value");
|
|
||||||
label.setCaption("Label");
|
|
||||||
gridLayout.addComponent(label);
|
|
||||||
|
|
||||||
final Link link = new Link("Baeldung", new ExternalResource("http://www.baeldung.com/"));
|
|
||||||
link.setId("Link");
|
|
||||||
link.setTargetName("_blank");
|
|
||||||
gridLayout.addComponent(link);
|
|
||||||
|
|
||||||
final TextField textField = new TextField();
|
|
||||||
textField.setId("TextField");
|
|
||||||
textField.setCaption("TextField:");
|
|
||||||
textField.setValue("TextField Value");
|
|
||||||
textField.setIcon(VaadinIcons.USER);
|
|
||||||
gridLayout.addComponent(textField);
|
|
||||||
|
|
||||||
final TextArea textArea = new TextArea();
|
|
||||||
textArea.setCaption("TextArea");
|
|
||||||
textArea.setId("TextArea");
|
|
||||||
textArea.setValue("TextArea Value");
|
|
||||||
gridLayout.addComponent(textArea);
|
|
||||||
|
|
||||||
final DateField dateField = new DateField("DateField", LocalDate.ofEpochDay(0));
|
|
||||||
dateField.setId("DateField");
|
|
||||||
gridLayout.addComponent(dateField);
|
|
||||||
|
|
||||||
final PasswordField passwordField = new PasswordField();
|
|
||||||
passwordField.setId("PasswordField");
|
|
||||||
passwordField.setCaption("PasswordField:");
|
|
||||||
passwordField.setValue("password");
|
|
||||||
gridLayout.addComponent(passwordField);
|
|
||||||
|
|
||||||
final RichTextArea richTextArea = new RichTextArea();
|
|
||||||
richTextArea.setCaption("Rich Text Area");
|
|
||||||
richTextArea.setValue("<h1>RichTextArea</h1>");
|
|
||||||
richTextArea.setSizeFull();
|
|
||||||
|
|
||||||
Panel richTextPanel = new Panel();
|
|
||||||
richTextPanel.setContent(richTextArea);
|
|
||||||
|
|
||||||
final InlineDateField inlineDateField = new InlineDateField();
|
|
||||||
inlineDateField.setValue(LocalDate.ofEpochDay(0));
|
|
||||||
inlineDateField.setCaption("Inline Date Field");
|
|
||||||
horizontalLayout.addComponent(inlineDateField);
|
|
||||||
|
|
||||||
Button normalButton = new Button("Normal Button");
|
|
||||||
normalButton.setId("NormalButton");
|
|
||||||
normalButton.addClickListener(e -> {
|
|
||||||
label.setValue("CLICK");
|
|
||||||
});
|
|
||||||
buttonLayout.addComponent(normalButton);
|
|
||||||
|
|
||||||
Button tinyButton = new Button("Tiny Button");
|
|
||||||
tinyButton.addStyleName("tiny");
|
|
||||||
buttonLayout.addComponent(tinyButton);
|
|
||||||
|
|
||||||
Button smallButton = new Button("Small Button");
|
|
||||||
smallButton.addStyleName("small");
|
|
||||||
buttonLayout.addComponent(smallButton);
|
|
||||||
|
|
||||||
Button largeButton = new Button("Large Button");
|
|
||||||
largeButton.addStyleName("large");
|
|
||||||
buttonLayout.addComponent(largeButton);
|
|
||||||
|
|
||||||
Button hugeButton = new Button("Huge Button");
|
|
||||||
hugeButton.addStyleName("huge");
|
|
||||||
buttonLayout.addComponent(hugeButton);
|
|
||||||
|
|
||||||
Button disabledButton = new Button("Disabled Button");
|
|
||||||
disabledButton.setDescription("This button cannot be clicked");
|
|
||||||
disabledButton.setEnabled(false);
|
|
||||||
buttonLayout.addComponent(disabledButton);
|
|
||||||
|
|
||||||
Button dangerButton = new Button("Danger Button");
|
|
||||||
dangerButton.addStyleName("danger");
|
|
||||||
buttonLayout.addComponent(dangerButton);
|
|
||||||
|
|
||||||
Button friendlyButton = new Button("Friendly Button");
|
|
||||||
friendlyButton.addStyleName("friendly");
|
|
||||||
buttonLayout.addComponent(friendlyButton);
|
|
||||||
|
|
||||||
Button primaryButton = new Button("Primary Button");
|
|
||||||
primaryButton.addStyleName("primary");
|
|
||||||
buttonLayout.addComponent(primaryButton);
|
|
||||||
|
|
||||||
NativeButton nativeButton = new NativeButton("Native Button");
|
|
||||||
buttonLayout.addComponent(nativeButton);
|
|
||||||
|
|
||||||
Button iconButton = new Button("Icon Button");
|
|
||||||
iconButton.setIcon(VaadinIcons.ALIGN_LEFT);
|
|
||||||
buttonLayout.addComponent(iconButton);
|
|
||||||
|
|
||||||
Button borderlessButton = new Button("BorderLess Button");
|
|
||||||
borderlessButton.addStyleName("borderless");
|
|
||||||
buttonLayout.addComponent(borderlessButton);
|
|
||||||
|
|
||||||
Button linkButton = new Button("Link Button");
|
|
||||||
linkButton.addStyleName("link");
|
|
||||||
buttonLayout.addComponent(linkButton);
|
|
||||||
|
|
||||||
Button quietButton = new Button("Quiet Button");
|
|
||||||
quietButton.addStyleName("quiet");
|
|
||||||
buttonLayout.addComponent(quietButton);
|
|
||||||
|
|
||||||
horizontalLayout.addComponent(buttonLayout);
|
|
||||||
|
|
||||||
final CheckBox checkbox = new CheckBox("CheckBox");
|
|
||||||
checkbox.setValue(true);
|
|
||||||
checkbox.addValueChangeListener(e -> checkbox.setValue(!checkbox.getValue()));
|
|
||||||
formLayout.addComponent(checkbox);
|
|
||||||
|
|
||||||
List<String> numbers = new ArrayList<String>();
|
|
||||||
numbers.add("One");
|
|
||||||
numbers.add("Ten");
|
|
||||||
numbers.add("Eleven");
|
|
||||||
ComboBox comboBox = new ComboBox("ComboBox");
|
|
||||||
comboBox.setItems(numbers);
|
|
||||||
formLayout.addComponent(comboBox);
|
|
||||||
|
|
||||||
ListSelect listSelect = new ListSelect("ListSelect");
|
|
||||||
listSelect.setItems(numbers);
|
|
||||||
listSelect.setRows(2);
|
|
||||||
formLayout.addComponent(listSelect);
|
|
||||||
|
|
||||||
NativeSelect nativeSelect = new NativeSelect("NativeSelect");
|
|
||||||
nativeSelect.setItems(numbers);
|
|
||||||
formLayout.addComponent(nativeSelect);
|
|
||||||
|
|
||||||
TwinColSelect twinColSelect = new TwinColSelect("TwinColSelect");
|
|
||||||
twinColSelect.setItems(numbers);
|
|
||||||
|
|
||||||
Grid<Row> grid = new Grid(Row.class);
|
|
||||||
grid.setColumns("column1", "column2", "column3");
|
|
||||||
Row row1 = new Row("Item1", "Item2", "Item3");
|
|
||||||
Row row2 = new Row("Item4", "Item5", "Item6");
|
|
||||||
List<Row> rows = new ArrayList();
|
|
||||||
rows.add(row1);
|
|
||||||
rows.add(row2);
|
|
||||||
grid.setItems(rows);
|
|
||||||
|
|
||||||
Panel panel = new Panel("Panel");
|
|
||||||
panel.setContent(grid);
|
|
||||||
panel.setSizeUndefined();
|
|
||||||
|
|
||||||
Panel serverPushPanel = new Panel("Server Push");
|
|
||||||
FormLayout timeLayout = new FormLayout();
|
|
||||||
timeLayout.setSpacing(true);
|
|
||||||
timeLayout.setMargin(true);
|
|
||||||
currentTime = new Label("No TIME...");
|
|
||||||
timeLayout.addComponent(currentTime);
|
|
||||||
serverPushPanel.setContent(timeLayout);
|
|
||||||
serverPushPanel.setSizeUndefined();
|
|
||||||
ScheduledExecutorService scheduleExecutor = Executors.newScheduledThreadPool(1);
|
|
||||||
Runnable task = () -> {
|
|
||||||
currentTime.setValue("Current Time : " + Instant.now());
|
|
||||||
};
|
|
||||||
scheduleExecutor.scheduleWithFixedDelay(task, 0, 1, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
FormLayout dataBindingLayout = new FormLayout();
|
|
||||||
dataBindingLayout.setSpacing(true);
|
|
||||||
dataBindingLayout.setMargin(true);
|
|
||||||
|
|
||||||
Binder<BindData> binder = new Binder<>();
|
|
||||||
BindData bindData = new BindData("BindData");
|
|
||||||
binder.readBean(bindData);
|
|
||||||
TextField bindedTextField = new TextField();
|
|
||||||
bindedTextField.setWidth("250px");
|
|
||||||
binder.forField(bindedTextField).bind(BindData::getBindName, BindData::setBindName);
|
|
||||||
dataBindingLayout.addComponent(bindedTextField);
|
|
||||||
|
|
||||||
FormLayout validatorLayout = new FormLayout();
|
|
||||||
validatorLayout.setSpacing(true);
|
|
||||||
validatorLayout.setMargin(true);
|
|
||||||
|
|
||||||
HorizontalLayout textValidatorLayout = new HorizontalLayout();
|
|
||||||
textValidatorLayout.setSpacing(true);
|
|
||||||
textValidatorLayout.setMargin(true);
|
|
||||||
|
|
||||||
|
|
||||||
BindData stringValidatorBindData = new BindData("");
|
|
||||||
TextField stringValidator = new TextField();
|
|
||||||
Binder<BindData> stringValidatorBinder = new Binder<>();
|
|
||||||
stringValidatorBinder.setBean(stringValidatorBindData);
|
|
||||||
stringValidatorBinder.forField(stringValidator)
|
|
||||||
.withValidator(new StringLengthValidator("String must have 2-5 characters lenght", 2, 5))
|
|
||||||
.bind(BindData::getBindName, BindData::setBindName);
|
|
||||||
|
|
||||||
textValidatorLayout.addComponent(stringValidator);
|
|
||||||
Button buttonStringValidator = new Button("Validate String");
|
|
||||||
buttonStringValidator.addClickListener(e -> stringValidatorBinder.validate());
|
|
||||||
textValidatorLayout.addComponent(buttonStringValidator);
|
|
||||||
|
|
||||||
validatorLayout.addComponent(textValidatorLayout);
|
|
||||||
verticalLayout.addComponent(gridLayout);
|
|
||||||
verticalLayout.addComponent(richTextPanel);
|
|
||||||
verticalLayout.addComponent(horizontalLayout);
|
|
||||||
verticalLayout.addComponent(formLayout);
|
|
||||||
verticalLayout.addComponent(twinColSelect);
|
|
||||||
verticalLayout.addComponent(panel);
|
|
||||||
verticalLayout.addComponent(serverPushPanel);
|
|
||||||
verticalLayout.addComponent(dataBindingLayout);
|
|
||||||
verticalLayout.addComponent(validatorLayout);
|
|
||||||
setContent(verticalLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
@WebServlet(urlPatterns = "/VAADIN/*", name = "MyUIServlet", asyncSupported = true)
|
|
||||||
@VaadinServletConfiguration(ui = VaadinUI.class, productionMode = false)
|
|
||||||
public static class MyUIServlet extends VaadinServlet {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.baeldung.introduction.basics;
|
||||||
|
|
||||||
|
import com.baeldung.data.Contact;
|
||||||
|
import com.vaadin.flow.component.button.Button;
|
||||||
|
import com.vaadin.flow.component.grid.Grid;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.component.splitlayout.SplitLayout;
|
||||||
|
import com.vaadin.flow.component.textfield.TextField;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Route("example-layout")
|
||||||
|
public class ExampleLayout extends SplitLayout {
|
||||||
|
|
||||||
|
public ExampleLayout() {
|
||||||
|
var grid = new Grid<>(Contact.class);
|
||||||
|
grid.setColumns("name", "email", "phone");
|
||||||
|
grid.setItems(List.of(
|
||||||
|
new Contact("John Doe", "john@doe.com", "123 456 789"),
|
||||||
|
new Contact("Jane Doe", "jane@doe.com", "987 654 321")
|
||||||
|
));
|
||||||
|
|
||||||
|
var form = new VerticalLayout();
|
||||||
|
|
||||||
|
var nameField = new TextField("Name");
|
||||||
|
var emailField = new TextField("Email");
|
||||||
|
var phoneField = new TextField("Phone");
|
||||||
|
var saveButton = new Button("Save");
|
||||||
|
var cancelButton = new Button("Cancel");
|
||||||
|
|
||||||
|
form.add(
|
||||||
|
nameField,
|
||||||
|
emailField,
|
||||||
|
phoneField,
|
||||||
|
new HorizontalLayout(saveButton, cancelButton)
|
||||||
|
);
|
||||||
|
|
||||||
|
setSizeFull();
|
||||||
|
setSplitterPosition(70);
|
||||||
|
addToPrimary(grid);
|
||||||
|
addToSecondary(form);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.baeldung.introduction.basics;
|
||||||
|
|
||||||
|
import com.vaadin.flow.component.html.H1;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
|
||||||
|
@Route("hello-world")
|
||||||
|
public class HelloWorldView extends VerticalLayout {
|
||||||
|
|
||||||
|
public HelloWorldView() {
|
||||||
|
add(new H1("Hello, World!"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package com.baeldung.introduction.basics;
|
||||||
|
|
||||||
|
import com.vaadin.flow.component.button.Button;
|
||||||
|
import com.vaadin.flow.component.checkbox.Checkbox;
|
||||||
|
import com.vaadin.flow.component.html.H1;
|
||||||
|
import com.vaadin.flow.component.notification.Notification;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.component.textfield.TextField;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
import com.vaadin.flow.router.RouterLink;
|
||||||
|
|
||||||
|
// The @Route annotation defines the URL path for the view
|
||||||
|
// Any component, most commonly a layout, can be used as a view
|
||||||
|
@Route("basics")
|
||||||
|
public class VaadinFlowBasics extends VerticalLayout {
|
||||||
|
public VaadinFlowBasics() {
|
||||||
|
|
||||||
|
// Add components to the layout with the add method
|
||||||
|
add(new H1("Vaadin Flow Basics"));
|
||||||
|
|
||||||
|
// Components are Java objects
|
||||||
|
var textField = new TextField("Name");
|
||||||
|
var button = new Button("Click me");
|
||||||
|
|
||||||
|
// Layouts define the structure of the UI
|
||||||
|
var verticalLayout = new VerticalLayout(
|
||||||
|
new Button("Top"),
|
||||||
|
new Button("Middle"),
|
||||||
|
new Button("Bottom")
|
||||||
|
);
|
||||||
|
add(verticalLayout);
|
||||||
|
|
||||||
|
var horizontalLayout = new HorizontalLayout(
|
||||||
|
new Button("Left"),
|
||||||
|
new Button("Center"),
|
||||||
|
new Button("Right")
|
||||||
|
);
|
||||||
|
add(horizontalLayout);
|
||||||
|
|
||||||
|
// Layouts can be nested for more complex structures
|
||||||
|
var nestedLayout = new VerticalLayout(
|
||||||
|
new HorizontalLayout(new Button("Top Left"), new Button("Top Right")),
|
||||||
|
new HorizontalLayout(new Button("Bottom Left"), new Button("Bottom Right"))
|
||||||
|
);
|
||||||
|
add(nestedLayout);
|
||||||
|
|
||||||
|
add(new RouterLink("Example layout", ExampleLayout.class));
|
||||||
|
|
||||||
|
// Use RouterLink to navigate to other views
|
||||||
|
var link = new RouterLink("Hello world view", HelloWorldView.class);
|
||||||
|
add(link);
|
||||||
|
|
||||||
|
// Use events to react to user input
|
||||||
|
var nameField = new TextField("Your name");
|
||||||
|
var helloButton = new Button("Say hello");
|
||||||
|
helloButton.addClickListener(e -> {
|
||||||
|
Notification.show("Hello, " + nameField.getValue());
|
||||||
|
});
|
||||||
|
add(nameField, helloButton);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
package com.baeldung.spring;
|
||||||
|
|
||||||
|
import com.baeldung.data.Employee;
|
||||||
|
import com.vaadin.flow.component.Composite;
|
||||||
|
import com.vaadin.flow.component.Key;
|
||||||
|
import com.vaadin.flow.component.button.Button;
|
||||||
|
import com.vaadin.flow.component.button.ButtonVariant;
|
||||||
|
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.component.textfield.TextField;
|
||||||
|
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||||
|
import com.vaadin.flow.data.binder.Binder;
|
||||||
|
|
||||||
|
public class EmployeeEditor extends Composite<VerticalLayout> {
|
||||||
|
|
||||||
|
public interface SaveListener {
|
||||||
|
void onSave(Employee employee);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface DeleteListener {
|
||||||
|
void onDelete(Employee employee);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface CancelListener {
|
||||||
|
void onCancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Employee employee;
|
||||||
|
|
||||||
|
private SaveListener saveListener;
|
||||||
|
private DeleteListener deleteListener;
|
||||||
|
private CancelListener cancelListener;
|
||||||
|
|
||||||
|
private final Binder<Employee> binder = new BeanValidationBinder<>(Employee.class);
|
||||||
|
|
||||||
|
public EmployeeEditor() {
|
||||||
|
var firstName = new TextField("First name");
|
||||||
|
var lastName = new TextField("Last name");
|
||||||
|
|
||||||
|
var save = new Button("Save", VaadinIcon.CHECK.create());
|
||||||
|
var cancel = new Button("Cancel");
|
||||||
|
var delete = new Button("Delete", VaadinIcon.TRASH.create());
|
||||||
|
|
||||||
|
binder.forField(firstName).bind("firstName");
|
||||||
|
binder.forField(lastName).bind("lastName");
|
||||||
|
|
||||||
|
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||||
|
save.addClickListener(e -> save());
|
||||||
|
save.addClickShortcut(Key.ENTER);
|
||||||
|
|
||||||
|
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
|
||||||
|
delete.addClickListener(e -> deleteListener.onDelete(employee));
|
||||||
|
|
||||||
|
cancel.addClickListener(e -> cancelListener.onCancel());
|
||||||
|
|
||||||
|
getContent().add(firstName, lastName, new HorizontalLayout(save, cancel, delete));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void save() {
|
||||||
|
// Save the form into a new instance of Employee
|
||||||
|
var updated = new Employee();
|
||||||
|
updated.setId(employee.getId());
|
||||||
|
|
||||||
|
if (binder.writeBeanIfValid(updated)) {
|
||||||
|
saveListener.onSave(updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmployee(Employee employee) {
|
||||||
|
this.employee = employee;
|
||||||
|
binder.readBean(employee);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSaveListener(SaveListener saveListener) {
|
||||||
|
this.saveListener = saveListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeleteListener(DeleteListener deleteListener) {
|
||||||
|
this.deleteListener = deleteListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCancelListener(CancelListener cancelListener) {
|
||||||
|
this.cancelListener = cancelListener;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
package com.baeldung.spring;
|
||||||
|
|
||||||
|
import com.baeldung.data.Employee;
|
||||||
|
import com.baeldung.data.EmployeeRepository;
|
||||||
|
|
||||||
|
import com.vaadin.flow.component.button.Button;
|
||||||
|
import com.vaadin.flow.component.grid.Grid;
|
||||||
|
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.component.textfield.TextField;
|
||||||
|
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
|
||||||
|
@Route("employees")
|
||||||
|
public class EmployeesView extends VerticalLayout {
|
||||||
|
|
||||||
|
private final EmployeeRepository employeeRepository;
|
||||||
|
|
||||||
|
private final TextField filter;
|
||||||
|
private final Grid<Employee> grid;
|
||||||
|
private final EmployeeEditor editor;
|
||||||
|
|
||||||
|
|
||||||
|
public EmployeesView(EmployeeRepository repo) {
|
||||||
|
employeeRepository = repo;
|
||||||
|
|
||||||
|
// Create components
|
||||||
|
var addButton = new Button("New employee", VaadinIcon.PLUS.create());
|
||||||
|
filter = new TextField();
|
||||||
|
grid = new Grid<>(Employee.class);
|
||||||
|
editor = new EmployeeEditor();
|
||||||
|
|
||||||
|
// Configure components
|
||||||
|
configureEditor();
|
||||||
|
|
||||||
|
addButton.addClickListener(e -> editEmployee(new Employee()));
|
||||||
|
|
||||||
|
filter.setPlaceholder("Filter by last name");
|
||||||
|
filter.setValueChangeMode(ValueChangeMode.LAZY);
|
||||||
|
filter.addValueChangeListener(e -> updateEmployees(e.getValue()));
|
||||||
|
|
||||||
|
grid.setHeight("200px");
|
||||||
|
grid.asSingleSelect().addValueChangeListener(e -> editEmployee(e.getValue()));
|
||||||
|
|
||||||
|
// Compose layout
|
||||||
|
var actionsLayout = new HorizontalLayout(filter, addButton);
|
||||||
|
add(actionsLayout, grid, editor);
|
||||||
|
|
||||||
|
// List customers
|
||||||
|
updateEmployees("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureEditor() {
|
||||||
|
editor.setVisible(false);
|
||||||
|
|
||||||
|
editor.setSaveListener(employee -> {
|
||||||
|
var saved = employeeRepository.save(employee);
|
||||||
|
updateEmployees(filter.getValue());
|
||||||
|
editor.setEmployee(null);
|
||||||
|
grid.asSingleSelect().setValue(saved);
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.setDeleteListener(employee -> {
|
||||||
|
employeeRepository.delete(employee);
|
||||||
|
updateEmployees(filter.getValue());
|
||||||
|
editEmployee(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.setCancelListener(() -> {
|
||||||
|
editEmployee(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void editEmployee(Employee employee) {
|
||||||
|
editor.setEmployee(employee);
|
||||||
|
|
||||||
|
if (employee != null) {
|
||||||
|
editor.setVisible(true);
|
||||||
|
} else {
|
||||||
|
// Deselect grid
|
||||||
|
grid.asSingleSelect().setValue(null);
|
||||||
|
editor.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateEmployees(String filterText) {
|
||||||
|
if (filterText.isEmpty()) {
|
||||||
|
grid.setItems(employeeRepository.findAll());
|
||||||
|
} else {
|
||||||
|
grid.setItems(employeeRepository.findByLastNameStartsWithIgnoreCase(filterText));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
/* This file is automatically managed and will be overwritten from time to time. */
|
|
||||||
/* Do not manually edit this file. */
|
|
||||||
|
|
||||||
/* Import and include this mixin into your project theme to include the addon themes */
|
|
||||||
@mixin addons {
|
|
||||||
}
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 30 KiB |
|
@ -1,38 +0,0 @@
|
||||||
// If you edit this file you need to compile the theme. See README.md for details.
|
|
||||||
|
|
||||||
// Global variable overrides. Must be declared before importing Valo.
|
|
||||||
|
|
||||||
// Defines the plaintext font size, weight and family. Font size affects general component sizing.
|
|
||||||
//$v-font-size: 16px;
|
|
||||||
//$v-font-weight: 300;
|
|
||||||
//$v-font-family: "Open Sans", sans-serif;
|
|
||||||
|
|
||||||
// Defines the border used by all components.
|
|
||||||
//$v-border: 1px solid (v-shade 0.7);
|
|
||||||
//$v-border-radius: 4px;
|
|
||||||
|
|
||||||
// Affects the color of some component elements, e.g Button, Panel title, etc
|
|
||||||
//$v-background-color: hsl(210, 0%, 98%);
|
|
||||||
// Affects the color of content areas, e.g Panel and Window content, TextField input etc
|
|
||||||
//$v-app-background-color: $v-background-color;
|
|
||||||
|
|
||||||
// Affects the visual appearance of all components
|
|
||||||
//$v-gradient: v-linear 8%;
|
|
||||||
//$v-bevel-depth: 30%;
|
|
||||||
//$v-shadow-opacity: 5%;
|
|
||||||
|
|
||||||
// Defines colors for indicating status (focus, success, failure)
|
|
||||||
//$v-focus-color: valo-focus-color(); // Calculates a suitable color automatically
|
|
||||||
//$v-friendly-color: #2c9720;
|
|
||||||
//$v-error-indicator-color: #ed473b;
|
|
||||||
|
|
||||||
// For more information, see: https://vaadin.com/book/-/page/themes.valo.html
|
|
||||||
// Example variants can be copy/pasted from https://vaadin.com/wiki/-/wiki/Main/Valo+Examples
|
|
||||||
|
|
||||||
@import "../valo/valo.scss";
|
|
||||||
|
|
||||||
@mixin mytheme {
|
|
||||||
@include valo;
|
|
||||||
|
|
||||||
// Insert your own theme rules here
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
@import "mytheme.scss";
|
|
||||||
@import "addons.scss";
|
|
||||||
|
|
||||||
// This file prefixes all rules with the theme name to avoid causing conflicts with other themes.
|
|
||||||
// The actual styles should be defined in mytheme.scss
|
|
||||||
|
|
||||||
.mytheme {
|
|
||||||
@include addons;
|
|
||||||
@include mytheme;
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue