I have a main Layout that contains another UI with grid and a button. This grid shows the data of a table of my database. With the button a wizard gets open, where i can create a new entry to this database. When i close the wizard with a button click, i want the grid to refresh in order to show also the newly added entry. Everythin works fine, including the storage to my database, except the refresh of my grid.
So i have the UI
public class MainLayout{
...
public void refreshGrid()
{
this.grid.getDataProvider().refreshAll();
}
}
where my grid is defined. I already implemented the refresh method.In there is also the button to create a new entry. When i click this button the next UI gets called.
This UI contains the general layout of the wizard, with a tab bar.
public class WizardLayout{
}
In one of those tabs there is finally the UI with the input fields to create the entry. There is also the button to save it to the database.
public class CreateEntry{
...
private void button_onClick(ClickEvent<Button> event)
{
...
}
}
In this button click method the logic is implemented to save it. And after that i would like to call the refresh method from the first UI in order to refresh it. How do i do that, so that it works?
Please remember, everything else works. So my only problem is to refresh the grid because it does not automatically. I have to click the refresh button in my browser to make it work.
First note that while not incorrect, your use of the term UI might be confusing in a Vaadin context, as it's usually used to refer to Vaadin UI objects, of which there is generally one per tab. Communication between Vaadin UIs is more complex than your use case.
There are plenty of solutions for this, the easiest is probably to pass an instance of your MainLayout to your wizard.
In that case, the classes will be tightly coupled, i.e. both depend on each other.
A better way is with some kind of listener or callback. This can be made quite complex, but in the easiest case you just pass a callback that will be run on save.
WizardLayout.java
private final Runnable saveCallback;
public WizardLayout(Runnable saveCallback) {
this.saveCallback = saveCallback;
}
private void button_onClick(ClickEvent<Button> event) {
...
saveCallback.run();
}
MainLayout.java
new WizardLayout(this::refreshGrid);
Is your dataprovider using in-memory items, or do you use a callback dataprovider with lazy loading?
You are probably using an in-memory dataprovider. This is the case, when you load your items from the database and put them in the grid with
grid.setItems(fooService.findAll());
Calling grid.getDataProvider().refresh() will only refresh the items that are already set. Since you have a new item to display, you have to fetch all items again from the DB with your service.
grid.setItems(fooService.findAll());
grid.getDataProvider().refreshAll();
If you're using a callback dataprovider with lazy loading, then I think just refreshing the dataprovider should be enough. I don't know enough about lazy loaded dataproviders to provide a solution to this issue but I do believe this issue should not arise in the first place if using a callback dataprovider
Related
I'm dealing with a WebApp (Vaadin19) and stuck now in the question, how to share an object-state change from one component to another. There is one object instance in two or more components. After changing an attribute of the object in one component and going back to another component, I want to see the changed attribute.
Let me explain, what I mean:
There is a grid with some lines of data. The grid shows only a subset of the data to respect the clarity.
A click on the grid opens a detailed view in "read mode". The data is structured (contains sub-objects itself).
A click on the "read mode"-view opens then a dialog with tabs. The activated tab depends on the sub-object, that was clicked before.
After changing an element in the sub-object and closing the dialog, I want that the UI will reload/revalidate it's content. I think it's clear, that I use there the same object-instance.
Is there an event I have to submit to the UI?
Or:
What is the best approach for this?
The actual refresh is easy: theGrid.getDataProvider().refreshAll(), or refreshItem instead if you have access to the item that has been changed and it has a good implementation of equals and hashCode.
How to hook things up so that the dialog notifies the grid is then really depending on your architecture.
If they are already close to each other in the code, then you could e.g. store a reference to the Grid in an instance field and just reference that in the dialog handler.
If you want to decouple, then you need some kind of event bus. You can use the regular Spring event mechanisms as long as you ensure that the event stays within the UI scope. Alternatively, you can use ComponentUtil::addListener and ComponentUtil::fireEvent to use e.g. UI.getCurrent as a simple event bus.
I have an application where a TableView will be created dynamically based on a database query. This means that my application will have multiple tables with differing columns.
I must display a separate button to show/hide columns. I am familiar with the table menu button triggered with table.setTableMenuButtonVisible(). Unfortunately, I cannot use the actual on-screen built-in button on the UI, although I would like to use it's functionality.
I am essentially looking for a table.getTableMenu().show()
sort of call. But I can't find where this is a built in method of any sort. Is there a way that I can call this button's action from a UI button of my own design?
Actually, I was wrong in my comment: it is possible to lookup the corner region and trigger its mousePressedHandler without reflection.
The following code snippet opens the corner menu just as if it had been clicked directly (in fx11 at least, and still dirty in relying on the implementation detail that opening is triggered by a mousePressed event):
Button showCorner = new Button("open menu button");
showCorner.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
Node corner = table.lookup(".show-hide-columns-button");
corner.fireEvent(e);
});
Right now I'm working in a big smartgwt project. I need to implement a nice feature but I have no idea how to do it.
Our application has a lots of forms located in different tabs and grids and so on. Each form has his own save button and when it gets pressed it performs some few actions before the save action. For the application, it is really important to only save the form when the user presses the button. What I need is some kind of handler to prevent a user leaving unsaved forms. My intention is to show some kind of warning popup but I have no idea how to bind the action.
I don't know even if it's possible to do something like that with smartgwt but it seems to me a very typical feature to have in a big web application.
Some ideas? Someone had this problem before?
You can intercept almost every user action in GWT. If you want for example to prevent user from leaving page you can use something like this:
Window.addWindowClosingHandler(new Window.ClosingHandler() {
#Override
public void onWindowClosing(ClosingEvent event) {
if (unsavedData) {
event.setMessage("There is unsaved data. Do you really want to leave?");
}
}
});
If you want to stop user on different action like closing tab you can also do that by adding proper event listener.
Determining whether there is some unsaved data is also fairly simple but depends on UI component.
For example in listGrid you can use listGrid.getAllEditRows().lenght
In form you can compare form.getOldValues() with form.getValues() (Guava library will be perfect for this task: Maps.difference(form.getOldValues(), form.getValues()).areEqual()) Maybe there is better way to check unsaved data in form but I don't know it.
And last problem - linking it all together. I created custom save controller with multiple save participants. With this approach you can ask controller.isThereAnyUnsavedData() and controller should ask each participant.
We are using the GWT provided SimplePager to provide record/page navigation through data sets. We want to test that we are controlling the enabled state of the Next/Previous buttons properly. While SimplePager lets us specify enabled/disabled images for the buttons, the "button" itself is an internal class of ImageButton which extends Image rather than Button. Therefore the resulting HTML does not use Button enabled/disabled attributes, but rather provides a different embedded image for each state.
Is there any reasonable way to detect the SimplePager navigation button enabled states in Selenium?
In standard practice you should create custom component, let say Image button. I would suggest you to use ISFW which provides feature of creating custom component that can be used with annotation. In component you can specify behavior in as per AUT.
Re-writing the code sample to have better formatting.
public class ImageButton extends Component{
public ImageButtom (String loc){
super(locator);
}
#Override
public boolean isEnabled() {
//custom representation!...
return this.getAttribute("class").contains("imgdisabled");
//return this.getCssValue("background").contains("imgdisabled");
//return this.getAttribute("src").contains("imgdisabled");
}
}
You can use this component like Webelement in your test page
#FindBy(locator="locator")
ImageButton prevButton;
#FindBy(locator="locator")
ImageButton nextButton;
In your test code
page.prevButton.verifyEnabled();
page.prevButton.assertEnabled();
Looking at the source code of SimplePager, it looks like they use a generator to create the css styles, where the disabled state (and the enabled state) has a css class applied to it (i m going off this https://code.google.com/p/google-web-toolkit/source/browse/trunk/user/src/com/google/gwt/user/cellview/client/SimplePager.java?r=9614).
So if you can somehow get access to the actual Resources client bundle, then you can call resources.simplePagerStyle().disabledButton() to get a string that is the css class for the disabled button, and you can then use that as a locator in selenium. That might be really tricky tho, because the jvm running your selenium test may not be able to reference the compiled GWT code (i.e., the code that runs when you debug a GWT app).
Alternatively, you can subclass SimplePager, instead of using the DEFAULT_RESOURCES client bundle, pass in your own, and then you get to control the classname used for the disabled button (by making your own Style class, which just wraps the existing one you get from the original client bundle, but add a prefix or something to the return value).
It's a bit messy, because the component is quite encapsulated, and you are trying to get at its innards.
When writing a graphical interface, using Java, what's the appropriate way of switching between the different windows of the application, when clicking a button for example? I.E. what are the windows supposed to be, JPanels, JFrames...? And how do all the components 'see' the 'domain controller' (the class that links the graphical package to the application logic package)?
Any guide or reference would be appreciated.
You start your application with your Controller. In the constructor of your controller, you are going to initialize the first GUI you want to open, lets say GUI_A:
private GUI_A gui_a = null;
Controller() {
gui_a = new GUI_A(this);
}
As you might notice, I called the constructor of GUI_A with one parameter: this. this is referencing the instance of the current class, so this is type of Controller. The constructor of GUI_A has to look something like this:
private Controller controller = null;
GUI_A(Controller ctrl) {
controller = ctrl;
}
This is a simple way to get the GUI known to the Controller.
The next thing you would do is displaying GUI_A:
gui_a.setVisible(true);
If you now want to handle button-clicks, you would do it like this:
First, you add the action-performed method to your button. And, as it is best practice in MVC, you don't want to do logic in your view/GUI. So you also create a corresponding method in your Controller for the action-performed, and call it from your GUI:
// Controller
GUI_A_button1_actionPerformed(ActionEvent evt) {
// Add your button logic here
}
// GUI_A
button1_actionPerformed(ActionEvent evt) {
controller.GUI_A_button1_actionPerformed(evt);
}
Usually you don't need to pass the ActionEvent-var to the Controller, as you will not need it often. More often you would read a text out of a TextField and pass it on to your Controller:
// Controller
GUI_A_button1_actionPerformed(String text) {
// Add logic for the text here
}
// GUI_A
button1_actionPerformed(ActionEvent evt) {
controller.GUI_A_button1_actionPerformed(textField1.getText());
}
If you now want to access some fields on your GUI_A from the Controller, be sure not to mark the fields as public in your GUI, but to create public methods which handle how to display the values.
The preferable way is using Actions. You can attach action to each control. When user action happens (e.g. click on button) the appropriate Action is called. Actions can delegate calls deeper into the application logic and call graphical components (JFrams, etc).
suggestion: use tabbed-panel should do this, JPanel is just a Java container, while JFrame should be the outside windows, they are different things. there should be several JPanels on top of One JFrame. your app can have multiple JFrames.
When writing a graphical interface, using Java, what's the appropriate way of switching between the different windows of the application, when clicking a button for example?
Add an ActionListener to the button. In the actionPerformed(ActionEvent) method, do what needs to be done.
I.E. what are the windows supposed to be, JPanels, JFrames...?
I would recommend making the main window a JFrame and using either a JDialog or JOptionPane for most of the other elements. Alternately, multiple GUI elements can be added into a single space in a number of ways - CardLayout, JTabbedPane, JSplitPane, JDesktopPane/JInternalFrame, ..
And how do all the components 'see' the 'domain controller' (the class that links the graphical package to the application logic package)?
One way is to pass a reference to the object between the UIs.