I've got window class implementation with annotation #Component. Inside this class I declare object with annotation #Autowired.
On my window form I've got a button Create which should read data from TextFields, create new object and store it in the database.
#Component("newProjectWindow")
public class NewProjectWindow {
private Window createProjectWindow;
#Autowired
private ProjectService service;
public Window createWindow() {
createProjectWindow = new Window("New project");
initWindow();
fillWindow();
return createProjectWindow;
}
private void initWindow() {
createProjectWindow.setSizeUndefined();
createProjectWindow.setResizable(false);
createProjectWindow.setModal(true);
createProjectWindow.addCloseListener(new CloseListener(){
#Override
public void windowClose(CloseEvent e) {
Notification.show("Closed");
}
});
}
private void fillWindow() {
final TextField projectName = new TextField("Project name");
final TextField projectOwner = new TextField("Project owner");
Button create = new Button("Create");
create.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
Project newProject = new Project();
newProject.setProjectName(projectName.getValue());
newProject.setProjectOwner(projectOwner.getValue());
//save it somehow
}
});
Button close = new Button("Cancel");
close.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
createProjectWindow.close();
}
});
HorizontalLayout layout = new HorizontalLayout(create, close);
FormLayout formLayout = new FormLayout(projectName, projectOwner, layout);
formLayout.setMargin(true);
createProjectWindow.setContent(formLayout);
}
}
However the problem is how to store object in the database. I've got no access to instantiated ProjectService(which uses ProjectRepisitory which uses SqlSessionTemplate and etc.) because it is under control of Spring - and anonymous ClickListener is not.
But how to store object?
I tend not to use anonymous inner methods for click listeners, but instead get my own classes to implement the ClickListner. So in your example I would change the class like this:
#Component("newProjectWindow")
public class NewProjectWindow {
private Window createProjectWindow implements Button.ClickListener;
#Autowired
private ProjectService service;
private Button create = new Button("Create", this);
private Button cancel new Button("Cancel", this);;
public Window createWindow() {
createProjectWindow = new Window("New project");
initWindow();
fillWindow();
return createProjectWindow;
}
private void initWindow() {
createProjectWindow.setSizeUndefined();
createProjectWindow.setResizable(false);
createProjectWindow.setModal(true);
createProjectWindow.addCloseListener(new CloseListener(){
#Override
public void windowClose(CloseEvent e) {
Notification.show("Closed");
}
});
}
private void fillWindow() {
final TextField projectName = new TextField("Project name");
final TextField projectOwner = new TextField("Project owner");
HorizontalLayout layout = new HorizontalLayout(create, close);
FormLayout formLayout = new FormLayout(projectName, projectOwner, layout);
formLayout.setMargin(true);
createProjectWindow.setContent(formLayout);
}
#Override
public void buttonClick(ClickEvent event) {
if (event.getButton() == cancel)
{
createProjectWindow.close();
}
else
{
Project newProject = new Project();
newProject.setProjectName(projectName.getValue());
newProject.setProjectOwner(projectOwner.getValue());
//save it somehow
}
}
}
To access service from listener in your example, consider following solutions:
Anonymous inner classes can reference outer class (using OuterClassName.this syntax - in your case NewProjectWindow.this.service).
You can declare (inner) class and pass appropriate references to it.
You can use Chris M suggestion of parent class implementing listener interface itself.
Related
I have a boot app that I am adding some crud screens to. I decided to use Vaadin and it seems to work great until I deploy it to a multi-nodal production environment.
Once in the prod environment the screens constantly refresh for no apparent reason. For example there is a grid in one screen that when a row is clicked a dialog pops up that shows item details. but as soon as the dialog pops up the page refreshes numerous times.
This forum thread here https://vaadin.com/forum/thread/17586129/routerlayout-causing-page-refresh is an example of the same layout I am using and describes a very similar issue.
I have a base abstract class that extends VerticalLayout and all of the concrete classes extend this base abstract class. Each concrete class defines its own route and use a common layout class.
I have reached out on gitter, vaadin forum and opened a bug in github but no one from Vaadin want to respond to anything as far as I can tell.
Here are the versions of everything I am using:
Vaadin Flow version: 14
Java version: 12.0.1+12
OS version: Mac 10.14.5
Browser version: Fire Fox 70.0.1, Chrome 78.0.3904.97
Code snippets from my implementation:
Main View
#Slf4j
#RoutePrefix("v1/crud")
#Theme(value = Material.class, variant = Material.DARK)
public class MainView extends Div implements RouterLayout {
private H1 h1 = new H1("Vaadin Crud UI");
private HorizontalLayout header = new HorizontalLayout(h1);
private Div content = new Div();
private ApplicationContext context;
#Inject
public MainView(ApplicationContext context) {
this.context = context;
setSizeFull();
h1.setWidthFull();
content.setWidthFull();
header.setWidthFull();
header.setAlignItems(FlexComponent.Alignment.CENTER);
VerticalLayout navigationBar = new VerticalLayout();
navigationBar.setWidth("25%");
navigationBar.add(createNavigationButton("Home", VaadinIcon.HOME, ReportTab.class));
navigationBar.add(createNavigationButton("Batch Search", VaadinIcon.SEARCH, BatchSearchTab.class));
... a bunch more buttons
HorizontalLayout layout = new HorizontalLayout(navigationBar, content);
layout.setWidthFull();
VerticalLayout page = new VerticalLayout(header, layout);
page.setWidthFull();
add(page);
}
#Override
public void showRouterLayoutContent(HasElement hasElement) {
if (hasElement != null) {
Element newElement = hasElement.getElement();
if (newElement != null) {
content.removeAll();
content.getElement().appendChild(newElement);
}
}
}
private Button createNavigationButton(String caption, VaadinIcon icon, Class<? extends BaseEditor> editor) {
Button button = new Button(caption, icon.create());
button.addClickListener(event -> UI.getCurrent().navigate(editor));
button.addThemeVariants(ButtonVariant.MATERIAL_CONTAINED);
button.getStyle().set("background-color", "#00819D");
button.setWidthFull();
return button;
}
}
Base Component:
#Slf4j
#Data
#SpringComponent
#UIScope
public abstract class BaseEditor<P, B> extends VerticalLayout {
private final RememberMeService rememberMe;
private final P businessProcess;
protected Binder<B> binder;
protected Dialog editDialog = new Dialog();
protected Button save = new Button("Save", VaadinIcon.CHECK.create());
protected Button close = new Button("Close", VaadinIcon.EXIT.create());
protected Button delete = new Button("Delete", VaadinIcon.TRASH.create());
protected B bean;
private ChangeHandler changeHandler;
private boolean proceed = true;
public BaseEditor(P businessProcess, RememberMeService rememberMe) {
this.rememberMe = rememberMe;
this.businessProcess = businessProcess;
save.addClickListener(e -> save());
delete.addClickListener(e -> delete());
}
public abstract void delete();
public abstract void save();
protected abstract Component getContent();
protected void edit(B e) {
bean = e;
editDialog.open();
getBinder().setBean(e);
}
protected void initEditorPanel(Component... components) {
HorizontalLayout actions = new HorizontalLayout(save, close, delete);
VerticalLayout data = new VerticalLayout(components);
data.add(actions);
editDialog.removeAll();
editDialog.add(data);
getBinder().bindInstanceFields(this);
close.addClickListener(e -> editDialog.close());
}
public interface ChangeHandler {
void onChange();
}
void setChangeHandler(ChangeHandler h) {
changeHandler = h;
}
void errorDialog(String message) {
final Button close = new Button("Close", VaadinIcon.CLOSE.create());
H3 h3 = new H3(message);
final Dialog errorDialog = new Dialog(h3, close);
errorDialog.open();
close.addClickListener(e -> errorDialog.close());
}
BaseEditor filter(Predicate<B> predicate) {
Objects.requireNonNull(predicate);
proceed = predicate.test(bean);
return this;
}
void buttonConsumer(Consumer<B> consumer) {
if (!proceed) {
proceed = true;
return;
}
try {
consumer.accept(bean);
} catch (Exception e) {
errorDialog(e.getMessage());
} finally {
editDialog.close();
getChangeHandler().onChange();
}
}
void either(Consumer<B> whenTrue, Consumer<B> whenFalse) {
try {
if (proceed) {
whenTrue.accept(bean);
} else {
whenFalse.accept(bean);
}
} catch (Exception e) {
errorDialog(e.getMessage());
} finally {
proceed = true;
editDialog.close();
getChangeHandler().onChange();
}
}
}
Concrete Component:
#Slf4j
#Route(value = "search/batch", layout = MainView.class)
public class BatchSearchTab extends BaseEditor<BatchService, Batch> {
private TextField searchField1;
private TextField searchField2;
public BatchSearchTab(BatchService businessProcess, RememberMeService rememberMe) {
super(businessProcess, rememberMe);
binder = new Binder<>(Batch.class);
save.setIcon(VaadinIcon.REPLY.create());
save.setText("Replay");
delete.setIcon(VaadinIcon.CLOSE.create());
delete.setText("Cancel");
getContent();
}
#Override
public void delete() {
buttonConsumer(b -> getBusinessProcess().cancelBatch(b.getBatchId(), b.getUserAgent()));
}
#Override
public void save() {
filter(b -> b.isReplayable()).buttonConsumer(b -> getBusinessProcess().buildAndSendFile((getBean())));
}
#Override
public void edit(Batch batch) {
HorizontalLayout actions = new HorizontalLayout();
H2 h2 = new H2();
if (batch.isReplayable()) {
h2.setText("Would you like to replay the following.");
actions.add(save, delete, close);
} else {
h2.setText("This record is not eligible for replay.");
actions.add(close);
}
Label batchId = new Label("Correlation Id: " + batch.getBatchId());
Label txnCount = new Label("Transaction Count: " + batch.getTotalTxns());
Label txnAmount = new Label("Total: " + batch.getTotalBatchAmount());
VerticalLayout data = new VerticalLayout(h2, batchId, txnCount, txnAmount, actions);
data.add(actions);
editDialog.removeAll();
editDialog.add(data);
close.addClickListener(e -> editDialog.close());
editDialog.open();
getBinder().setBean(batch);
}
#Override
protected Component getContent() {
final H2 h2 = new H2("Locate Batches");
searchField1 = new TextField("Batch Code");
searchField2 = new TextField("User Agent");
searchField2.addKeyPressListener(Key.ENTER, e -> keyPressListener());
Button searchBtn = new Button("Search", VaadinIcon.SEARCH.create());
HorizontalLayout search = new HorizontalLayout(searchField1, searchField2);
searchBtn.addClickListener(e -> {
search(searchField1.getValue(), searchField2.getValue());
});
add(h2, search, searchBtn);
return this;
}
private void search(String code, String userAgent) {
log.info("Searching {} and {}", code, userAgent);
List<Batch> batches =
getBusinessProcess().getBatchesForUserAgent(code, userAgent, 60);
log.info("Found {} batches", batches.size());
if (batches.size() > 0) {
buildGrid(batches, "BatchId", "totalTxns", "totalBatchAmount", "status");
} else {
errorDialog("No Records found for criteria");
}
}
private void keyPressListener() {
String code = StringUtils.isNotBlank(searchField1.getValue()) ? searchField1.getValue() : null;
if (StringUtils.isNotBlank(searchField2.getValue())) {
search(code, searchField2.getValue());
}
}
private void buildGrid(Collection<Batch> records, String... columns) {
Component result;
if (records.size() == 0) {
result = new Label("NO REPORT DATA AVAILABLE.");
} else {
final Grid<Batch> grid = new Grid<>(Batch.class);
grid.setHeightByRows(records.size() < 10);
grid.setColumns(columns);
grid.setItems(records);
grid.setWidthFull();
grid.asSingleSelect().addValueChangeListener(l -> Optional.ofNullable(l.getValue()).ifPresent(this::edit));
result = grid;
}
if (getComponentCount() < 3) {
add(result);
} else {
replace(getComponentAt(2), result);
}
}
private void loadData(String code, String userAgent) {
if (StringUtils.isNotBlank(code)) {
search(null, userAgent);
} else {
search(code, userAgent);
}
}
}
Disclaimer: some further fact finding happended via IRC
The answer to the question is related to OP running multiple instances of the application behind an round robin load ballancer. The clients hit random servers and therefor had no session running there.
The solution to this is having a shared session store and ideally have the load ballancer dispatch on existing session, so "hot" backend servers get hit.
This is my code, some parts have been omitted (such as imports, psvm, etc.):
public class Proyect extends Application implements EventHandler{
private HBox menu1() {
Image food1 = new Image (getClass().getResourceAsStream("clipboard.png"));
Button btnR = new Button ("R", new ImageView(food1));
}
#Override
public void handle(Event event) {
if(event.getSource() == btnR) {
}
}
}
The problem is my IDE says I'm mistaken in the "btnR" thing inside my if statement (it's underlined in red).
Button btnR is defined within the method menu1(). Hence it won't be accessible within the method handle(). Why don't you define it within the class as a private data member?
Please use the logic as mentioned below:
public class Proyect extends Application implements EventHandler{
private Button btnR;
private HBox menu1() {
Image food1 = new Image (getClass().getResourceAsStream("clipboard.png"));
btnR = new Button ("R", new ImageView(food1));
}
#Override
public void handle(Event event) {
if(event.getSource() == btnR) {
}
}
}
I've been trying to build a simple GUI with JavaFX (I'm completely new to JavaFX) and I've found myself stuck. In every tutorial I've found event handling is done on the level of the UI object, mostly with annonymous inner classes - what I want to accomplish is to move the event handlers to controller class, and inject references to them trough methods called on controller's (and view's) instantiation.
My small GUI is properly build and displayed, the reference is indeed passed, but for a reason the handle() method is not invoked, and I can't find the reason why.
The View:
//imports here
public class View extends Application implements ViewInterface, Runnable {
private Menu fileMenu;
private Menu storheouseMenu;
private MenuBar menuBar;
private Scene scene;
private MenuItem exitItem;
public View() {
initialize();
}
public void initialize() {
fileMenu = new Menu("Plik");
storheouseMenu = new Menu("Magazyn");
MenuItem exitItem = new MenuItem("Exit");
MenuItem displayStorehouse = new MenuItem("Display");
fileMenu.getItems().addAll(exitItem);
storheouseMenu.getItems().add(0, displayStorehouse);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = new VBox();
scene = new Scene(root, 400, 200);
primaryStage.setScene(scene);
primaryStage.setTitle("Szefowa test");
menuBar = new MenuBar();
menuBar.getMenus().addAll(fileMenu, storheouseMenu);
((VBox) scene.getRoot()).getChildren().addAll(menuBar);
primaryStage.setResizable(false);
primaryStage.show();
}
public void addFileMenuListeners(EventHandler<ActionEvent> eventHandler) {
exitItem = fileMenu.getItems().get(0);
exitItem.setOnAction(eventHandler);
}
public void addStorehouseMenuListeners(EventHandler<ActionEvent> eventHandler) {
MenuItem displayStorehouse = fileMenu.getItems().get(0);
displayStorehouse.setOnAction(eventHandler);
}
public void displayMessage(String message) {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Ping");
alert.setContentText(message);
}
//other methods here
}
The Controller:
package kitke.szefowa.controller;
//imports here
public class Controller implements ControllerInterface {
private Model model;
private View view;
public Controller(Model model, View view) {
this.model = model;
this.view = view;
this.view.addFileMenuListeners(new FileMenuListener());
this.view.addStorehouseMenuListeners(new StorehouseMenuListener());
}
public class FileMenuListener implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent event) {
//do some stuff
}
}
public class StorehouseMenuListener implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent event) {
//do some stuff
}
}
}
}
PS I've no such problem while build the GUI with Swing so the issue is connected with JavaFX.
I have tested your code by manual instantiation as:
Controller controller = new Controller( this );
in View.start() method. The event handlers are working as expected with only small problem. Both in addFileMenuListeners() and addStorehouseMenuListeners() methods you are setting the event handler to the same menuitem fileMenu.getItems().get(0). So calling of these method one after another, second invocation is overriding the setOnAction of the first one.
So change the addStorehouseMenuListeners() to:
public void addStorehouseMenuListeners( EventHandler<ActionEvent> eventHandler )
{
MenuItem displayStorehouse = storheouseMenu.getItems().get(0);
displayStorehouse.setOnAction( eventHandler );
}
I've created a vaadin table. When I do right-click it shows context menu with +New... text and when I click on it - it shows modal window with two tables. Every table has the same fuctionality.
The problem is that every time I open and close modal window it adds duplicates for context menu items on modal tables(on the main page it works correct). Moreover - it adds several modal windows when I click on modal table context menu (for example if I open window 5 times - it add 5 context menu items and 5 modal windows for clicked modal context menus)
The only way to return to one item - restart whole application.
What is the problem?
Every my table looks like this
#Component("taskTable")
#Scope("prototype")
public class TaskTable extends AbstractObjectTable {
#Autowired
private TaskService taskService;
#Autowired
private NewTaskWindow taskWindow;
#Autowired
private ShowTaskDetailsWindow detailsWindow;
private Action[] action = new Action[] { new Action("+New...") };
#Override
public Table createTable() {
caption = "Tasks";
headers = new String[] { "Description", "Project", "Status", "Weight", "Developer", "ID" };
this.addActionHandler(new Handler() {
#Override
public Action[] getActions(Object target, Object sender) {
return action;
}
#Override
public void handleAction(Action action, Object sender, Object target) {
switch(action.getCaption()) {
case "+New...": {
PmcUi.getCurrent().addWindow(taskWindow.createWindow());
break;
}
}
//what to do for action
}
});
this.addItemClickListener(new ItemClickListener(){
#Override
public void itemClick(ItemClickEvent event) {
if (event.isDoubleClick()) {
PmcUi.getCurrent().addWindow(detailsWindow.createWindow());
}
return;
}
});
return super.createTable();
}
#Override
protected IndexedContainer projectDatasource() {
IndexedContainer indexedContainer = new IndexedContainer();
for(String header: headers) {
indexedContainer.addContainerProperty(header, String.class, "");
}
List<Task> tasks = taskService.findAllTasks();
for(int i = 0; i < tasks.size(); i++) {
Object id = indexedContainer.addItem();
Task item = tasks.get(i);
indexedContainer.getContainerProperty(id, headers[0]).setValue(item.getDescription());
indexedContainer.getContainerProperty(id, headers[1]).setValue(item.getTaskProject());
indexedContainer.getContainerProperty(id, headers[2]).setValue(item.getStatus());
indexedContainer.getContainerProperty(id, headers[3]).setValue(item.getWeight());
indexedContainer.getContainerProperty(id, headers[4]).setValue(item.getTaskDeveloper());
indexedContainer.getContainerProperty(id, headers[5]).setValue(item.getTaskId());
}
return indexedContainer;
}
}
Where AbstractObjectTable
public abstract class AbstractObjectTable extends Table {
protected String caption;
protected String[] headers = null;
protected Table createTable() {
this.setContainerDataSource(projectDatasource());
this.setVisibleColumns(headers);
this.setSelectable(true);
this.setImmediate(true);
return this;
}
protected abstract IndexedContainer projectDatasource();
}
My +New... modal windows looks similar to that
#Component("newTaskWindow")
public class NewTaskWindow {
private Window createTaskWindow;
#Autowired
private TaskService taskService;
public Window createWindow() {
createTaskWindow = new Window("New Task");
initWindow();
fillWindow();
return createTaskWindow;
}
private void initWindow() {
createTaskWindow.setSizeUndefined();
createTaskWindow.setResizable(false);
createTaskWindow.setModal(true);
createTaskWindow.addCloseListener(new CloseListener() {
#Override
public void windowClose(CloseEvent e) {
Notification.show("Closed");
}
});
}
private void fillWindow() {
final TextField taskDescription = new TextField("Description");
final ComboBox taskProject = new ComboBox("Select project");
final ComboBox taskDeveloper = new ComboBox("Select developer");
final TextField taskWeight = new TextField("Task weight");
final TextField taskStatus = new TextField("Task status");
Button create = new Button("Create");
create.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
Task task = new Task();
task.setTaskId(UUID.randomUUID().toString());
task.setStatus(taskStatus.getValue());
task.setTaskDeveloper(taskDeveloper.getValue().toString());
task.setTaskProject(taskProject.getValue().toString());
task.setWeight(taskWeight.getValue());
task.setDescription(taskDescription.getValue());
taskService.insertTask(task);
createTaskWindow.close();
}
});
Button close = new Button("Cancel");
close.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
createTaskWindow.close();
}
});
HorizontalLayout layout = new HorizontalLayout(create, close);
FormLayout formLayout = new FormLayout(taskProject, taskDeveloper, taskWeight, taskStatus,
taskDescription, layout);
formLayout.setMargin(true);
createTaskWindow.setContent(formLayout);
}
}
And my details windows also have similar architecture.
#Component("showTaskDetailsWindow")
public class ShowTaskDetailsWindow {
private Window showDetailsWindow;
#Autowired
private TaskService taskService;
public Window createWindow() {
showDetailsWindow = new Window("Show details");
initWindow();
fillWindow();
return showDetailsWindow;
}
private void initWindow() {
showDetailsWindow.setSizeUndefined();
showDetailsWindow.setResizable(false);
showDetailsWindow.setModal(true);
showDetailsWindow.addCloseListener(new CloseListener() {
#Override
public void windowClose(CloseEvent e) {
Notification.show("Closed");
}
});
}
private void fillWindow() {
final TextField taskDescription = new TextField("Description");
final TextField taskProject = new TextField("Task project");
final TextField taskDeveloper = new TextField("Task developer");
final TextField taskWeight = new TextField("Task weight");
final TextField taskStatus = new TextField("Task status");
FormLayout formLayout = new FormLayout(taskProject, taskDeveloper, taskWeight, taskStatus, taskDescription);
formLayout.setMargin(true);
showDetailsWindow.setContent(formLayout);
}
}
What is the problem? Why it is continuously multiplying?
The problem is your getActions implementation
#Override
public Action[] getActions(Object target, Object sender) {
return new Action[] { new Action("+New...")};
}
You should create one instance of the "new Action("+New...")" item and store it for example in the TaskTable object.
The getActions(..) should alsways return the same instance.
If you always create a new action, it just adds them to the already existing actions.
Looks like the createTable() method of the TaskTable class is called too many times but the provided code doesn't show where that method is called. That causes that multiple action handlers and item click listeners are added to a table.
I'm very new in Vaadin and JavaEE at all and I have I think basic question, but will be glad for help.
I have 3 classes in my Vaadin project, here they are:
Main class, responding only for starting and creating navigator:
public class MyprojectUI extends UI {
public Navigator navigator;
public static final String SECOND_VIEW = "SecondView";
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = MyprojectUI.class)
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
ComponentContainerViewDisplay viewDisplay = new ComponentContainerViewDisplay(layout);
navigator = new Navigator(UI.getCurrent(), viewDisplay);
navigator.addView("", new FirstView());
navigator.addView(SECOND_VIEW, new SecondView());
}
}
And two views class:
public class FirstView extends HorizontalLayout implements View {
TextArea text = new TextArea();
Button button = new Button("go");
#Override
public void enter(ViewChangeEvent event) {
this.addComponent(text);
this.addComponent(button);
button.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
getUI().getNavigator().navigateTo(MyprojectUI.SECOND_VIEW);
}
});
}
}
-
public class SecondView extends HorizontalLayout implements View {
Label label = new Label("Passed text here");
#Override
public void enter(ViewChangeEvent event) {
this.addComponent(label);
}
}
How can I pass a data from my TextArea to second view? I want set label text to text which was in TextArea when "go" button is clicked.
Thanks for help.
I recommend you apply Model-View-Presenter pattern. View is already made. Model is not needed here. Just write a Presenter.
In MVP, Presenter is triggered by view, then presenter collects required data from view, does some calculation and updates view. In current case it could look like:
class Presenter {
FirstView firstView;
SecondView secondView;
public Presenter (FirstView firstView, SecondView secondView) {
this.firstView = firstView;
this.secondView = secondView;
}
public void goClicked(UI ui) {
secondView.label.setValue(firstView.text.getValue());
ui.getNavigator().navigateTo(MyprojectUI.SECOND_VIEW);
}
}
Code is simplified, recommended practice is define an interface for view instead direct fields access, but main idea is the same.
SecondView secondView = new SecondView();
navigator.addView(SECOND_VIEW, secondView );
Presenter presenter = new Presenter(firstView, secondView);