Hi guys,
I’m new to Vaadin and it can be the case that my question is related to well-known kowledge -_-. I’m working with Vaadin 7 beta 5 and am using Navigator to navigate in my application. The UI is quite simple: on the left I’ve got a tree, which is populated with a model read from KB (at the moment it’s mockup) - I’m using HierarchicalContainer for it . Objects displayed in a tree are of different type. Now, when the user clicks on particular node in the tree, I want to show corresponding view in the right hand side part of the UI. That is fine, I call Navigator#navigateTo(…) and the virew appears.
My question is how can I pass in elegant way the clicked object (node) to the view. I don’t want the view to reach to the tree to avoid coupling. Please point me to any ideas - I’m happy to read more about topics which could be involved even if they’re prove to be big (e.g. data binding: I mention this, because I know how to use it with forms, but can’t imagine how could this API help me with my current problem, still I expect, that I might be wrong…).
Your objects should have (preferably persistent, such as database primary keys) IDs that can be conveniently represented as strings. Then you can simply pass the ID as a parameter in the navigation state and the browser location URL will automatically reflect the currently selected node.
class NodeView implements View {
public void enter(ViewChangeEvent e) {
displayNode(getNodeById(e.getParameters()))
}
// Implement displayNode and getNodeById somehow
}
...
navi.addView("node/", new NodeView());
...
// In your click listener
// Implement getClickedNodeId somehow
navi.navigateTo("node/" + getClickedNodeId());
Thank you for your answer.
The solution you’ve suggested is exatly the one I use, but instead of reaching to the item from a view, I store the item in a session and retrieve it in View#enter() method.
Note that storing it in the session won’t work if someone bookmarks or copypastes the location URI. Entering the URI in the browser should bring up the node referenced in the URI, not the one stored in the session (if any - the original session might be long gone by that time!)
Other thing that could be useful, is using an event bus to pass information between the views. On the target view you can subscribe the type of event, that is accompanied with all object information.
You can use something like Google Guava’s event bus.
This would help just in the area of responsiveness as you would not need to load the information again from the service, but be aware of not having “up-to-date” data if you go this way.
You would also need the View to have a valid like scope so it’s available to process the event when it’s triggered
I’m utilizing this approach with Vaadin 7.5.10. Calls to .navigateTo(…) work great, however I’ve noticed that navigating directly to the URL or refreshes result in enter() being called twice. How do you prevent this?
For this you have two direct alternatives:
One is using ApplicationEventPublisher from Spring
The second would be to use Guava’s event bus, very simple as well:
You register the view in the event bus and create a “subscribed” method (listener method) to some type of custom event. Then from somewhere else with access to the bus “post” an event that will be handled by this method and do whatever you need.
@SpringView(name = ViewNames.HOME)
public class HomeView extends VerticalLayout implements View {
@Autowired
private EventBus bus;
@Override
public void enter(ViewChangeListener.ViewChangeEvent viewChangeEvent) {
}
@PostConstruct
public void createView() { addComponent(testButton()); bus.register(this); }
private Button testButton() {
Button button = new Button("Click me");
button.setStyleName(ValoTheme.BUTTON_PRIMARY);
button.setStyleName(ValoTheme.BUTTON_HUGE);
button.addClickListener(clickEvent -> { Notification.show("Test", "Test message", Notification.Type.TRAY_NOTIFICATION); }); return button;
}
@Subscribe
public void onChangeSomeValue(SomeValueChangeEvent event) {
// do whatever need here
}
}
For this method to be called:
bus.post(new SomeValueChangeEvent());
Of course you need the bus also injected and available from where you call it.
You could pass everything you need encapsulated in the event. This dependes completely on your implementation.
IMHO this is a great approach to achieve what you want and also many other things. Completely decouples what happens from what needs to be done.
I have two views. In one view I have a Grid with some data and there is an ‘Edit’ button next to each record in the grid. When I click the ‘Edit’ button, the second view should open with the field populated with values of the record of the grid from the first view. I don’t know how to implement the same as I started learning Vaadin recently.