Vaadin-Tutorials


CSS Selectors

The following CSS selectors can be used in stylesheets to target the various parts and states of the component. See the Styling documentation for more details on how to style components.

-------------------------------------------------------------------------------------------------------

Accordion



@Route("accordion-basic")
public class AccordionBasic extends Div
{
//Creating a constructor
public AccordionBasic()
{
Accordion accordion = new Accordion();

Span name = new Span("Deepesh Dhaundiyal");
Span email = new Span("deepeshd@kognosdata.com");
Span phone = new Span("+91 798-2600-xxx");

VerticalLayout info = new VerticalLayout(name,email, phone);

info.setSpacing(false);
info.setPadding(false);

accordion.add("Personal Details" , info);

Span houseAddress = new Span("D-1 A block Janakouri");
Span picode = new Span("110010");
Span city = new Span("Delhi");

VerticalLayout buildingAddressLayout = new VerticalLayout();
buildingAddressLayout.setPadding(false);
buildingAddressLayout.setSpacing(false);
buildingAddressLayout.add(houseAddress, picode, city);

accordion.add("Office Building Address" , buildingAddressLayout);

add(accordion);
}
}


Anatomy

Accordion consists of stacked panels, each composed of two parts: a summary and a content area. Only one panel can be expanded at a time. Use the Details component to allow multiple, simultaneously expanded sections.


Summary

The summary is the part that’s always visible, and typically describes the content, for example, with a title. Clicking on the summary toggles the content area’s visibility.

The summary supports rich content and can contain any component. This can be utilized, for example, to display the status of the corresponding content.



Reverse Accordion



@Route("")
public class AccordionReversePannel extends Div
{

public AccordionReversePannel()
{

Accordion accordion = new Accordion();

Span name = new Span("Deep");
Span company = new Span("KognosData");
Span email = new Span("mymailid@company.com");

VerticalLayout personalDetailsLayout = new VerticalLayout(name,company,email);

personalDetailsLayout.setSpacing(false);
personalDetailsLayout.setPadding(false);

AccordionPanel personalDetailsPannel = accordion.add("Personal Information",personalDetailsLayout);
personalDetailsPannel.addThemeVariants(DetailsVariant.REVERSE);

Span street = new Span ("Street no. 1");
Span pincode = new Span("110011");
Span city = new Span("Delhi");

VerticalLayout buildingAddressLayout = new VerticalLayout();

buildingAddressLayout.setPadding(false);
buildingAddressLayout.setSpacing(false);

buildingAddressLayout.add(street, pincode, city);

AccordionPanel buildingAddressPanel = accordion.add("Building Address", buildingAddressLayout);

buildingAddressPanel.addThemeVariants(DetailsVariant.REVERSE);

add(accordion);




}

}


--------------------------------------------------------------

App Layout

https://vaadin.com/docs/latest/components/app-layout


package com.example.application.views.list.AppLayout;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouterLink;

@Route("")
public class Basic extends AppLayout
{

public Basic()
{
DrawerToggle toggle = new DrawerToggle();

H1 tittle = new H1("My App");

tittle.getStyle().set("font-size","var(--lumo-font-size-l)").set("margin","0");

Tabs tabs = getTabs();

addToDrawer(tabs);
addToNavbar(toggle,tittle);
}

private Tabs getTabs()
{
Tabs tabs = new Tabs();
tabs.add(createTab(VaadinIcon.DASHBOARD, "Dashboard"),
createTab(VaadinIcon.CART, "Orders"),
createTab(VaadinIcon.USER_HEART, "Customers"),
createTab(VaadinIcon.PACKAGE, "Products"),
createTab(VaadinIcon.RECORDS, "Documents"),
createTab(VaadinIcon.LIST, "Tasks"),
createTab(VaadinIcon.CHART, "Analytics"));

tabs.setOrientation(Tabs.Orientation.VERTICAL);

return tabs;
}

private Component createTab(VaadinIcon viewIcon, String viewName)
{
Icon icon = viewIcon.create();
icon.getStyle().set("box-sizing", "border-box")
.set("margin-inline-end", "var(--lumo-space-m)")
.set("margin-inline-start", "var(--lumo-space-xs)")
.set("padding", "var(--lumo-space-xs)");

RouterLink link = new RouterLink();
link.add(icon, new Span(viewName));

// Demo has no routes
// link.setRoute(viewClass.java);
link.setTabIndex(-1);

return new Tab(link);

}
}

Navigation Bar Placement || Navbar Placement

The navbar can be located on top or to the side of the drawer.

When put on top, the navbar is typically used as an application header. Application headers contain, for example, the application’s name and branding, as well as actions that apply to the entire application, such as notifications, settings, etc.


package com.example.application.views.list.AppLayout;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.router.RouterLink;

public class NavBarPlacement extends AppLayout
{

public NavBarPlacement()
{
DrawerToggle drawerToggle = new DrawerToggle();

H1 tittle = new H1("MyApp");

tittle.getStyle().set("font-size","var(--lumo-font-size-l)").set("margin","0");

Tabs tabs = getTabs();

addToDrawer(tabs);
addToNavbar(drawerToggle, tittle);

}

private Tabs getTabs() {

Tabs tabs = new Tabs();

tabs.add(createTab(VaadinIcon.DASHBOARD, "Dashboard"),
createTab(VaadinIcon.CART, "Orders"),
createTab(VaadinIcon.USER_HEART, "Customers"),
createTab(VaadinIcon.PACKAGE, "Products"),
createTab(VaadinIcon.RECORDS, "Documents"),
createTab(VaadinIcon.LIST, "Tasks"),
createTab(VaadinIcon.CHART, "Analytics"));

tabs.setOrientation(Tabs.Orientation.VERTICAL);
return tabs;
}

private Component createTab(VaadinIcon viewIcon, String nameView)
{
Icon icon = viewIcon.create();
icon.getStyle().set("box-sizing", "border-box")
.set("margin-inline-end", "var(--lumo-space-m)")
.set("margin-inline-start", "var(--lumo-space-xs)")
.set("padding", "var(--lumo-space-xs)");

RouterLink link = new RouterLink();
link.add(icon, new Span(nameView));

link.setTabIndex(-1);

return new Tab(link);

}

}



When placed to the side, the navbar is often seen as a view header, housing the view’s title, and actions and secondary navigation that relate only to the current view.


package com.example.application.views.list.AppLayout;

import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouterLink;

@Route("")
public class NavBarPlacementSide extends AppLayout
{

public NavBarPlacementSide()
{
DrawerToggle toggle = new DrawerToggle();

H1 title = new H1("Dashboard");
title.getStyle().set("font-size", "var(--lumo-font-size-l)")
.set("margin", "0");

Tabs tabs = getTabs();

addToDrawer(tabs);
addToNavbar(toggle, title);

setPrimarySection(Section.DRAWER);
}

private Tabs getTabs()
{
Tabs tabs = new Tabs();
tabs.add(createTab(VaadinIcon.DASHBOARD, "Dashboard"),
createTab(VaadinIcon.CART, "Orders"),
createTab(VaadinIcon.USER_HEART, "Customers"),
createTab(VaadinIcon.PACKAGE, "Products"),
createTab(VaadinIcon.RECORDS, "Documents"),
createTab(VaadinIcon.LIST, "Tasks"),
createTab(VaadinIcon.CHART, "Analytics"));

tabs.setOrientation(Tabs.Orientation.VERTICAL);

return tabs;
}

private Tab createTab(VaadinIcon viewIcon, String viewName)
{
Icon icon = viewIcon.create();
icon.getStyle().set("box-sizing", "border-box")
.set("margin-inline-end", "var(--lumo-space-m)")
.set("padding", "var(--lumo-space-xs)");

RouterLink link = new RouterLink();
link.add(icon,new Span(viewName));

link.setTabIndex(-1);

return new Tab(link);
}
}



Auto height


When the App Layout has an undefined/auto height, which is the default behavior, the <body> element is the scrolling container for the content inside the layout.

package com.example.application.views.list.AppLayout;

import java.util.List;

import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.html.H1;
import com.vaadin.demo.domain.Person;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.router.Route;
import com.vaadin.demo.domain.DataService;

@Route("")
// tag::snippet[]
public class AppLayoutHeightAuto extends AppLayout {

public AppLayoutHeightAuto() {
H1 title = new H1("MyApp");
title.getStyle().set("font-size", "var(--lumo-font-size-l)")
.set("margin", "var(--lumo-space-m)");
addToNavbar(title);

Grid<Person> grid = new Grid<>(Person.class, false);
grid.addColumn(Person::getFirstName).setHeader("First name");
grid.addColumn(Person::getLastName).setHeader("Last name");
grid.addColumn(Person::getEmail).setHeader("Email");
grid.addColumn(Person::getProfession).setHeader("Profession");

List<Person> people = DataService.getPeople(20);
grid.setItems(people);
grid.setAllRowsVisible(true);
setContent(grid);
}
// end::snippet[]

// tag::snippet[]
}
// end::snippet[]


Bottom Navbar on Small Touchscreens

When the navbar is used for navigation, the touch-optimized navbar slot can be used to provide a separate version of the navigation at the bottom of the UI, optimized for mobile phones.




https://vaadin.com/docs/latest/components/app-layout/#navbar-placement




--------------------------------------------------------------------

BUTTON


package com.example.application.views.list.button;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.router.Route;

@Route
public class Basic extends Div
{

int counter = 0 ;

public Basic()
{
Button button = new Button();
Paragraph info = new Paragraph("Button");
button.addClickListener(buttonClickEvent -> {
counter += 1;
info.setText(infoText());
});

HorizontalLayout horizontalLayout = new HorizontalLayout(button , info);
horizontalLayout.setAlignItems(FlexComponent.Alignment.BASELINE);
add(horizontalLayout);
}

private String infoText()
{
return String.format("Clicked %d times" , counter);
}

}




--------------------------------------------------------------------

Keeping two buttons side by side || next to each other

Button button = new Button("Click me");
DatePicker datePicker = new DatePicker("Please select a Date!");

HorizontalLayout horizontalLayout = new HorizontalLayout(button,datePicker);

add(horizontalLayout);

Alignment

HorizontalLayout horizontalLayout = new HorizontalLayout(button,datePicker);

horizontalLayout.setDefaultVerticalComponentAlignment(Alignment.AUTO);
add(horizontalLayout);

Button Event Handling || Adding click event

Button button = new Button("Click me");
DatePicker datePicker = new DatePicker("Please select a Date!");

HorizontalLayout horizontalLayout = new HorizontalLayout(button,datePicker);

horizontalLayout.setDefaultVerticalComponentAlignment(Alignment.END);
add(horizontalLayout);

button.addClickListener(click -> add(new Paragraph("Clicked: " + datePicker.getValue())));
TextField filterText = new TextField();

private HorizontalLayout getToolbar() {
filterText.setPlaceholder("Filter by name...");
filterText.setClearButtonVisible(true);
filterText.setValueChangeMode(ValueChangeMode.LAZY);

Button addContactButton = new Button("Add contact");
add(addContactButton, filterText);
//Event

var toolbar = new HorizontalLayout(filterText, addContactButton);
toolbar.addClassName("toolbar");
return toolbar;
}
Search Button example :-
Creating a search filter || TextField
package com.example.application.views.list;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Paragraph;
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.PageTitle;

@PageTitle("MyFirstPage")
public class MainView extends VerticalLayout
{

public MainView()
{

Button button = new Button("Search");
TextField textField = new TextField("Enter text to be search...");
// DatePicker datePicker = new DatePicker("Please select a Date!");

//HorizontalLayout horizontalLayout = new HorizontalLayout(button,datePicker);
HorizontalLayout horizontalLayout = new HorizontalLayout(textField,button);

VerticalLayout verticalLayout = new VerticalLayout(textField,button);
verticalLayout.setDefaultHorizontalComponentAlignment(Alignment.BASELINE);
add(verticalLayout);

button.addClickListener(click -> add(new Paragraph("Searched for : " + textField.getValue())));

}

}



Creating a contact list || contact form


package com.example.application.views.list;

import com.example.application.data.entity.Contact;
import com.vaadin.flow.component.Component;
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.textfield.TextField;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;

@PageTitle("Contacts || Vaadin CRM")
@Route("")
public class ContactList extends VerticalLayout
{
Grid<Contact> grid = new Grid<>(Contact.class);
TextField textField = new TextField();

//Loading a constructor for class ContactList
public ContactList()
{
addClassName("contact-list");
setSizeFull();

//Calling a configureGrid-method to configure grid for our contact-list page.
configureGrid();

//Adding toolbar and grid to our page
add(
getToolbar(),
grid
);
}

private Component getToolbar()
{
textField.setPlaceholder("Search by name...");
textField.setClearButtonVisible(true);

//Lazy bcz we want to fetch result from DB once user complete typing the word "deep" not only for 1-by-1 letter "d,e,e,p"
textField.setValueChangeMode(ValueChangeMode.LAZY);
textField.setValueChangeMode(ValueChangeMode.LAZY);
//textField.addValueChangeListener(e -> updateList());

//Adding a button to our toolbar to perform some action.
Button button = new Button("SEARCH!");

//Now setting horizontal layout for button and textField in our page
HorizontalLayout toolbar = new HorizontalLayout(textField, button);
//Setting class name to apply CSS later on
toolbar.addClassName("toolbar");

return toolbar;

}

public void configureGrid()
{
//Adding class name for CSS file
grid.addClassName("contact-grid");
grid.setSizeFull();

grid.setColumns("firstName","lastName","email");

grid.addColumn(contact -> contact.getCompany().getName()).setHeader("Company");
grid.addColumn(contact -> contact.getStatus().getName()).setHeader("Status");

}

}

CREATING A BUTTON LAYOUT || BUTTONS LAYOUT 
//Create Button object for createButtonLayout-method
Button save = new Button("Save Contact");
Button delete = new Button("Delete Contact");
Button cancel = new Button("Cancel Contact");
private Component createButtonLayout()
{

save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
cancel.addThemeVariants(ButtonVariant.LUMO_TERTIARY);

save.addClickShortcut(Key.ENTER);
cancel.addClickShortcut(Key.ESCAPE);

return new HorizontalLayout(save, delete, cancel);
}

BUTOONS ARE SHOWN BELOW IN CONTACT FORM FOR REFERENCE IMAGE

Creating a contact form || contact details 

@PageTitle("Contacts || Vaadin CRM")
@Route("")
public class ContactList extends VerticalLayout
{
Grid<Contact> grid = new Grid<>(Contact.class);
TextField textField = new TextField();

ContactFormList form;
//Loading a constructor for class ContactList
public ContactList()
{
addClassName("contact-list");
setSizeFull();

//Calling a configureGrid-method to configure grid for our contact-list page.
configureGrid();
configureForm();

//Adding toolbar and grid to our page
add(
getToolbar(),
getContent()
);
}

private Component getContent() {
HorizontalLayout content = new HorizontalLayout(grid, form);
content.setFlexGrow(2,grid);
content.setFlexGrow(1,form);
content.addClassName("content");
content.setSizeFull();

return content;
}

private void configureForm() {
form = new ContactFormList(Collections.emptyList(), Collections.emptyList());
form.setWidth("25em");
}

private Component getToolbar()
{
textField.setPlaceholder("Search by name...");
textField.setClearButtonVisible(true);

//Lazy bcz we want to fetch result from DB once user complete typing the word "deep" not only for 1-by-1 letter "d,e,e,p"
textField.setValueChangeMode(ValueChangeMode.LAZY);
textField.setValueChangeMode(ValueChangeMode.LAZY);
//textField.addValueChangeListener(e -> updateList());

//Adding a button to our toolbar to perform some action.
Button button = new Button("SEARCH!");

//Now setting horizontal layout for button and textField in our page
HorizontalLayout toolbar = new HorizontalLayout(textField, button);
//Setting class name to apply CSS later on
toolbar.addClassName("toolbar");

return toolbar;

}

public void configureGrid()
{
//Adding class name for CSS file
grid.addClassName("contact-grid");
grid.setSizeFull();

grid.setColumns("firstName","lastName","email");

grid.addColumn(contact -> contact.getCompany().getName()).setHeader("Company");
grid.addColumn(contact -> contact.getStatus().getName()).setHeader("Status");

}

}
package com.example.application.views.list;

import com.example.application.data.entity.Company;
import com.example.application.data.entity.Status;
import com.vaadin.flow.component.Component;
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.combobox.ComboBox;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;

import java.util.List;

public class ContactFormList extends FormLayout
{
TextField firstName = new TextField("First Name");
TextField lastName = new TextField("Last Name");
TextField email = new TextField("Email-ID");

//To be understood...???????
ComboBox<Status> status = new ComboBox<>("Status");
ComboBox<Company> company = new ComboBox<>("Company");


//Create Button object for createButtonLayout-method
Button save = new Button("Save Contact");
Button delete = new Button("Delete Contact");
Button cancel = new Button("Cancel Contact");
//Loading constructor...
public ContactFormList(List<Company> companies, List <Status> statuses)
{

addClassName("contact-form-list");
company.setItems(companies);
//To be understood...???????
company.setItemLabelGenerator(Company::getName);

status.setItems(statuses);
status.setItemLabelGenerator(Status :: getName);

add(
firstName, lastName, email, company, status,
createButtonLayout()
);

}

private Component createButtonLayout()
{

save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
cancel.addThemeVariants(ButtonVariant.LUMO_TERTIARY);

save.addClickShortcut(Key.ENTER);
cancel.addClickShortcut(Key.ESCAPE);

return new HorizontalLayout(save, delete, cancel);
}


}

CONNECTING TO THE DATA BASE :-
( crm-service for BSNS logic & contact repository- For DB query )

https://github.com/vaadin/flow-crm-tutorial/blob/v24/src/main/java/com/example/application/data/repository/ContactRepository.java

https://www.youtube.com/watch?v=bxy2JgqqKDU   - 35:00 mins





---------------------------------------------------

 Step 1: Download a Vaadin Project

Download   Open in online IDE

Unpack the downloaded zip into a folder on your computer, and import the project in the IDE of your choice. (Alternatively, open the project in an online IDE).

Step 2: Add Your Code to given location file:-

Open src/main/java/org/vaadin/example/MainView.java

Replace the code in Main-View with the code below:-

//This @Route annotation makes the view accessible to the end user, in this case, using the empty `` route.@Route("") 1
public class MainView extends VerticalLayout { 2 //As the the MainView class extends VerticalLayout, components added to it will be ordered //vertically.
public MainView() { VerticalLayout todosList = new VerticalLayout(); 3
// todosList is a vertical layout that displays a list of the tasks along with checkboxes.
TextField taskField = new TextField(); 4 //is a text input field to enter the description of new tasks. Button addButton = new Button("Add"); 5 //is a button for adding a new task. addButton.addClickListener(click -> { 6 //in the listener for the button click, first create a                    new checkbox with the value from the taskField as its label, then add the checkbox                  to the todosList. Checkbox checkbox = new Checkbox(taskField.getValue()); todosList.add(checkbox); }); addButton.addClickShortcut(Key.ENTER); 7   Set a shortcut for the                                        addButton component when the Enter key is pressed. add( 8  Call add() on the VerticalLayout to display the components vertically. Notice that  taskField and addButton are in a HorizontalLayout, which puts them next to each other.
new H1("Vaadin Todo"), todosList, new HorizontalLayout( taskField, addButton ) ); } }


package com.example.application.views.list;

import com.vaadin.flow.component.Key;
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.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;

@Route("")
public class MainView extends VerticalLayout {

public MainView() {
VerticalLayout todosList = new VerticalLayout();
TextField taskField = new TextField();
Button addButton = new Button("Add");
addButton.addClickListener(click -> {
Checkbox checkbox = new Checkbox(taskField.getValue());
todosList.add(checkbox);
});
addButton.addClickShortcut(Key.ENTER);

add(
new H1("Create your task list"),
todosList,
new HorizontalLayout(
taskField,
addButton
)
);
}
}


Creating Components Using Composition

Vaadin Flow is a component-based framework. You’ve already worked with several components, like GridTextField, and VerticalLayout. But, the real power of the component-based architecture is in the ability to create your own components.

Instead of building an entire view in a single class, your view can be composed of smaller components that each handle different parts of the view. The advantage of this approach is that individual components are easier to understand and test. The top-level view is used mainly to orchestrate the components.

Creating a Form Component

The form component you will create has:

  • Text fields for the first and last name.

  • An email field.

  • Two select fields: one to select the company and the other to select the contact status.

Create a new file, ContactForm.java, in the com.example.application.views.list package. If you are using IntelliJ, copy the code below and paste it into the views package. IntelliJ will automatically create the file.


package com.example.application.views.list;

import com.example.application.data.entity.Company;
import com.example.application.data.entity.Status;
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.combobox.ComboBox;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.EmailField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;

import java.util.List;

@Route("")
//public class ContactForm extends VerticalLayout {
//public class ContactForm extends HorizontalLayout {
public class ContactForm extends FormLayout {
//ContactForm extends FormLayout, a responsive
// layout that shows form fields in 1 or 2 columns
// depending on viewport width.



//Creating all the UI components as fields required in the Form component.
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
EmailField email = new EmailField("Email");
ComboBox<Status> status = new ComboBox<>("Status");
ComboBox<Company> company = new ComboBox<>("Company");

Button save = new Button("Save");
Button delete = new Button("Delete");
Button close = new Button("Cancel");

//Gives the component a CSS class name,
// so you can style it later.
public ContactForm(List<Company> companies, List<Status> statuses) {
addClassName("contact-form");

company.setItems(companies);
company.setItemLabelGenerator(Company::getName);
status.setItems(statuses);
status.setItemLabelGenerator(Status::getName);

//Adds all the UI components to the layout.
//The buttons require a bit of extra configuration.
// Create and call a new method, createButtonsLayout().
add(firstName,
lastName,
email,
company,
status,
createButtonsLayout());
}

/* private HorizontalLayout createButtonsLayout1() {
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);

save.addClickShortcut(Key.ENTER);
close.addClickShortcut(Key.ESCAPE);

return new HorizontalLayout(save, delete, close);
}*/

private VerticalLayout createButtonsLayout()
{
//Makes the buttons visually distinct from
// each other using built-in theme variants.
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);

//Defines keyboard shortcuts:
//Enter to save and Escape to close the editor.
save.addClickShortcut(Key.ENTER);
close.addClickShortcut(Key.ESCAPE);

//Returns a VerticalLayout containing
//the buttons to place them next to each other.
return new VerticalLayout(save, delete, close);
}
}


CREATING A FROM COMPONENT:-

ContactForm.java class


package com.example.application.views.list;

import com.example.application.data.entity.Company;
import com.example.application.data.entity.Status;
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.combobox.ComboBox;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.EmailField;
import com.vaadin.flow.component.textfield.TextField;

import java.util.List;

public class ContactForm extends FormLayout {
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
EmailField email = new EmailField("Email");
ComboBox<Status> status = new ComboBox<>("Status");
ComboBox<Company> company = new ComboBox<>("Company");

Button save = new Button("Save");
Button delete = new Button("Delete");
Button close = new Button("Cancel");

public ContactForm(List<Company> companies, List<Status> statuses) {
addClassName("contact-form");

company.setItems(companies);
company.setItemLabelGenerator(Company::getName);
status.setItems(statuses);
status.setItemLabelGenerator(Status::getName);

add(firstName,
lastName,
email,
company,
status,
createButtonsLayout());
}

private HorizontalLayout createButtonsLayout() {
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);

save.addClickShortcut(Key.ENTER);
close.addClickShortcut(Key.ESCAPE);

return new HorizontalLayout(save, delete, close);
}
}

MainView.java class :-

package com.example.application.views.list;

import com.example.application.data.entity.Contact;
import com.vaadin.flow.component.Component;
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.textfield.TextField;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;

import java.util.Collections;

@Route("")
@PageTitle("Contacts | Vaadin CRM")
public class ListView extends VerticalLayout {
Grid<Contact> grid = new Grid<>(Contact.class);
TextField filterText = new TextField();

ContactForm form;

HorizontalLayout horizontalLayout = new HorizontalLayout();
public ListView() {



addClassName("list-view");
setSizeUndefined();
configureGrid();
configureForm();

add(getToolbar(), getContent());
}

private void configureGrid() {
grid.addClassNames("contact-grid");
grid.setSizeFull();
grid.setColumns("firstName", "lastName", "email");
grid.addColumn(contact -> contact.getStatus().getName()).setHeader("Status");
grid.addColumn(contact -> contact.getCompany().getName()).setHeader("Company");
grid.getColumns().forEach(col -> col.setAutoWidth(true));
horizontalLayout.add(grid);

}

private HorizontalLayout getToolbar() {
filterText.setPlaceholder("Filter by name...");
filterText.setClearButtonVisible(true);
filterText.setValueChangeMode(ValueChangeMode.LAZY);

Button addContactButton = new Button("Add contact");
add(addContactButton, filterText);
//Event

var toolbar = new HorizontalLayout(filterText, addContactButton);
toolbar.addClassName("toolbar");
return toolbar;
}

private Component getContent() {
HorizontalLayout content = new HorizontalLayout(grid, form);
content.setFlexGrow(2, grid);
content.setFlexGrow(1, form);
content.addClassNames("contact-form");
content.addClassNames("list-view");
content.setSizeFull();
content.add(grid,form);
return content;
}

private void configureForm() {
form = new ContactForm(Collections.emptyList(), Collections.emptyList());
form.setWidth("25em");
}
}




Layouts

Layouts decide how components are positioned in the browser window. The most common layout components are HorizontalLayoutVerticalLayout, and Div. The first two set the content orientation as horizontal or vertical, whereas Div lets you control the positioning with CSS


HorizontalLayout and VerticalLayout have methods to align items on both the primary and the cross axis. For example, if you want all components, regardless of their height, to be aligned with the bottom of a HorizontalLayout, you can set the default alignment to Alignment.END.

Using this example, and the add() method to add components to layouts, you would do something like this:

Button button = new Button("I'm a button");
HorizontalLayout layout = new HorizontalLayout(button, new DatePicker("Pick a date"));

layout.setDefaultVerticalComponentAlignment(Alignment.END);
add(layout);


UI Events

You can add functionality to your application by listening to events. Events can include button clicks and value changes from select components.

This example adds the text "Clicked!" to the layout when the button is clicked:

button.addClickListener(clickEvent ->
  add(new Text("Clicked!")));

HTML

One unique Vaadin Flow feature is that you can build web applications entirely in Java, eliminating the need to write common HTML. This higher level of abstraction makes development more productive and debugging easier.

Vaadin does support HTML templates and customizing the code that runs in the browser. However, you don’t usually have to worry about this.

The Contact List View

The first view is the Contact list view. You can see how it looks in the screenshot here. It lists all contacts. Users can search, add, edit, and delete contacts in this view.

You’ll focus initially only on the list view. You’ll add a layout containing the header and sidebar later on the "Navigation & App Layout" part.

On this part and the next, you’ll create the required layouts and components for the view. Then, on the part that follows, you’ll create a service class for accessing the backend and populating the view with data.













Flow CRM Tutorial

This project can be used as a starting point to create your own Vaadin application with Spring Boot. It contains all the necessary configuration and some placeholder files to get you started.

Running the application

The project is a standard Maven project. To run it from the command line, type mvnw (Windows), or ./mvnw (Mac & Linux), then open http://localhost:8080 in your browser.

You can also import the project to your IDE of choice as you would with any Maven project. Read more on how to import Vaadin projects to different IDEs (Eclipse, IntelliJ IDEA, NetBeans, and VS Code).

Deploying to Production

To create a production build, call mvnw clean package -Pproduction (Windows), or ./mvnw clean package -Pproduction (Mac & Linux). This will build a JAR file with all the dependencies and front-end resources, ready to be deployed. The file can be found in the target folder after the build completes.

Once the JAR file is built, you can run it using java -jar target/flowcrmtutorial-1.0-SNAPSHOT.jar

Project structure

  • MainLayout.java in src/main/java contains the navigation setup (i.e., the side/top bar and the main menu). This setup uses App Layout.
  • views package in src/main/java contains the server-side Java views of your application.
  • views folder in frontend/ contains the client-side JavaScript views of your application.
  • themes folder in frontend/ contains the custom CSS styles.

Useful links

Deploying using Docker

To build the Dockerized version of the project, run

mvn clean package -Pproduction docker build . -t flowcrmtutorial:latest

Once the Docker image is correctly built, you can test it locally using

docker run -p 8080:8080 flowcrmtutorial:latest

















Comments