Disable ValueChangeListener - vaadin

I'm new of vaadin and now I'm running in the following trouble. I have a TabSheet that contains a few tabs.
Now my Tax Code component setted in immediate mode and others it has a the following ValueChangeLister
TextField taxCode = new TextField();
taxCode.setImmediate(true);
taxCode.addValueChangeListener(new ValueChangeListener() {
#Override
public void valueChange(ValueChangeEvent event) {
if(taxCode.isModified()){
searchByTaxCode(taxCode.getValue());
}
}
});
then each time that the user changes the value to taxCode component, the method searchByTaxCode is invoked. This happens also when the user switch from Tab2 to Tab1 and I don't want this?
How can I fix this problem?

This simple test app does not fire the ValueChangeEvent when switching tabs, only when actually changing the value in the TextField. You have something more that could influence the behaviour?
public class TabSheetEventsUI extends UI {
#WebServlet(value = "/tabsheetevents/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = TabSheetEventsUI.class)
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
TabSheet tabSheet = new TabSheet();
Panel tab1 = new Panel("Tab 1");
Panel tab2 = new Panel("Tab 2");
tabSheet.addTab(tab1);
tabSheet.addTab(tab2);
final TextField tab1tf = new TextField("tab1tf");
tab1tf.setImmediate(true);
tab1tf.addValueChangeListener(new ValueChangeListener() {
#Override
public void valueChange(ValueChangeEvent event) {
System.out.println("Value change event catched.");
}
});
tab1.setContent(tab1tf);
setContent(tabSheet);
}
}

Related

Avoid refreshing of content in SplitLayout

I have a splitlayout in my vaadin application in which in the first column I should show different pages added through the addToPrimary method, while in the second column I should have a page which contains an IFrame with a videoconference. Now the problem is that when I change route in the first column, even the second is updated and this refreshes the IFrame. The implementation of the showRouterLayoyutContent is the following:
#Override
public void showRouterLayoutContent(HasElement content) {
if (this.accessControl.isAccessGranted(UI.getCurrent(), ((ContentView) content).getName()) && ((ContentView) content).getName().equals("contattaView") ) {
setLayoutCall((com.vaadin.flow.component.Component) content);
}
else if (this.accessControl.isAccessGranted(UI.getCurrent(), ((ContentView) content).getName())) {
setLayoutContent((com.vaadin.flow.component.Component) content);
}
}
And the two methods setLayoutCall and setLayoutContent are the following:
private void setLayoutContent(com.vaadin.flow.component.Component content) {
split.addToPrimary(content);
}
private void setLayoutCall(com.vaadin.flow.component.Component content) {
split.addToSecondary(content);
split.setThemeName("visible-split");
}
How can I avoid to refresh the entire content when I update the first column of the split layout through navigation?
UPDATE: I'm showing also a very simple code on which I'm testing. The following class is the main layout:
private SplitLayout split = new SplitLayout();
private HorizontalLayout hl = new HorizontalLayout();
private Div firstDiv = new Div();
private Div secondDiv = new Div();
public MainView() {
Button button = new Button("Click me",
event -> Notification.show("Clicked!"));
final VerticalLayout menuBar = new VerticalLayout();
menuBar.add(new RouterLink("first view", FirstView.class));
menuBar.add(new RouterLink("second view", SecondView.class));
menuBar.setAlignItems(Alignment.CENTER);
add(menuBar);
//split.addToPrimary(firstDiv);
//split.addToSecondary(secondDiv);
//firstDiv.setId("first");
//secondDiv.setId("second");
//hl.add(firstDiv,secondDiv);
add(split);
//add(hl);
}
#Override
public void showRouterLayoutContent(HasElement element) {
if(element!=null && element.getClass().getName().contains("FirstView")) {
split.addToPrimary((Component) element);
//firstDiv.removeAll();
//firstDiv.add((Component) element);
//firstDiv.removeAll();
//firstDiv.getElement().appendChild(new Element[]{element.getElement()});
}
else if(element!=null && element.getClass().getName().contains("SecondView") ) {
secondDiv.removeAll();
secondDiv.add((Component) element);
split.addToSecondary((Component) element);
//split.addToSecondary(element.getElement().getComponent().get());
}
}
While these are the two views added to the split:
#Route(value="v1",layout=MainView.class)
public class FirstView extends VerticalLayout implements RouterLayout {
public FirstView() {
add(new Label("First View"));
}
}
#Route(value = "v2",layout=MainView.class)
public class SecondView extends VerticalLayout implements RouterLayout {
public SecondView() {
IFrame frame = new IFrame();
frame.setSrc("https://www.youtube.com/watch?v=LoigVtPCYPk&list=RDLoigVtPCYPk&start_radio=1");
add(frame);
}
}
Your comment does indeed seem to be the issue.
I recommend creating a Div wrapper for the primary content, and instead changing the content of that.
private final Div wrapper;
public MyLayout() {
wrapper = new Div();
wrapper.setSizeFull();
split.addToPrimary(wrapper);
}
private void setLayoutContent(com.vaadin.flow.component.Component content) {
wrapper.removeAll();
wrapper.add(content);
}
You might also want to do the same for the secondary. In addition, to prevent any components from being automatically removed when navigating, you can override removeRouterLayoutContent as well (available in Vaadin 14)
#Override
public void removeRouterLayoutContent(HasElement oldContent) {
// Do nothing, we remove manually in showRouterLayoutContent
}
Edit
If you can't override removeRouterLayoutContent, you can try creating your own instance of the HasElement to add. This is a bit of a hack, but might be the simplest solution.
public void showRouterLayoutContent(HasElement content) {
if (content.getClass().getSimpleName().contains("TestView")) {
// Creating a new instance should stop it from being auto removed
content = new TestView();
firstDiv.add((Component) content);
}
...
}

OptionGroup addValueChangeListener CheckBox

Vaadin 7.6.5.
I am trying to figure out why a value change listener fails in the below case?
The CheckBox is observing for addValueChangeListener OptionGroup.
#Theme("vaadindemo")
public class VaadindemoUI extends UI {
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = VaadindemoUI.class)
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
OptionGroup group = new OptionGroup();
group.addItem("01");
group.setItemCaption("01", "ONE");
group.addItem("02");
group.setItemCaption("02", "TWO");
group.addItem("03");
group.setItemCaption("03", "THREE");
group.addValueChangeListener(new ValueChangeListener() {
#Override
public void valueChange(ValueChangeEvent event) {
System.out.println("group getValue " + event.getProperty().getValue());
System.out.println("group getType " + event.getProperty().getType());
}
});
CheckBox box = new CheckBox();
box.setCaption("Check Me");
//Notify CheckBox of value change of radio button
//group.addValueChangeListener(box); -- // Code Fails
//box.addValueChangeListener(group); // Selected Radio Button is removed
TextField field = new TextField();
field.addValueChangeListener(new ValueChangeListener() {
#Override
public void valueChange(ValueChangeEvent event) {
System.out.println("field getValue " + event.getProperty().getValue());
System.out.println("field getType " + event.getProperty().getType());
System.out.println("field getType " + field.getValue());
}
});
group.addValueChangeListener(field);// The value is reflected. How do i get only the event without over writing the value
//group.addValueChangeListener(box);
layout.addComponent(group);
layout.addComponent(box);
layout.addComponent(field);
Button button = new Button("Click Me");
button.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
layout.addComponent(new Label("Thank you for clicking"));
}
});
layout.addComponent(button);
}
}
It logs:
com.vaadin.data.util.converter.Converter$ConversionException: Unable to convert value of type java.lang.String to presentation type class java.lang.Boolean. No converter is set and the types are not compatible.
at com.vaadin.data.util.converter.ConverterUtil.convertFromModel(ConverterUtil.java:116)
at com.vaadin.ui.AbstractField.convertFromModel(AbstractField.java:736)
at com.vaadin.ui.AbstractField.convertFromModel(AbstractField.java:721)
at ...
I think you want something like...
group.addValueChangeListener(new ValueChangeListener() {
#Override
public void valueChange(ValueChangeEvent event) {
//Do something with box here? e.g...
box.setValue(!box.getValue());
}
});
rather than...
group.addValueChangeListener(box);

Vaadin, Switching Content via setContent() not displaying

Vaadin 7.6.2
Take the following example:
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
public class MyClass extends Panel {
TextField myField = new TextField();
HorizontalLayout hLayout = new HorizontalLayout( myField );
VerticalLayout vLayout = new VerticalLayout( myField );
Button button = new Button( "Press Me" );
public MyClass() {
super();
applySettings();
}
private void applySettings() {
button.addClickListener(new ClickListener() {
#Override
public void buttonClick(Button.ClickEvent event) {
setContent( hLayout );
}
});
vLayout.addComponent( button );
this.setContent( vLayout );
}
}
When I click the button the vLayout disappears but the hLayout (with myField) doesn't appear. What step am I'm missing? Or, is there a different way to do this?
If I add a secondary text field, like so:
TextField myField = new TextField();
TextField myField2 = new TextField(); // tf2
HorizontalLayout hLayout = new HorizontalLayout( myField );
VerticalLayout vLayout = new VerticalLayout( myField2 ); // tf2
It appears to work, however what I'm trying to achieve is the ability to dynamically switch my layouts using the fields (and their data) from the switched-out layout.
One component can not have 2 parents at the same time (hLayout & vLayout in your case), thus if it already has one, Vaadin will remove it from the previous parent and add it as a child to the current one. This is the addComponent method inherited from AbstractComponentContainer:
/**
* This only implements the events and component parent calls. The extending
* classes must implement component list maintenance and call this method
* after component list maintenance.
*
* #see com.vaadin.ui.ComponentContainer#addComponent(Component)
*/
#Override
public void addComponent(Component c) {
// Make sure we're not adding the component inside it's own content
if (isOrHasAncestor(c)) {
throw new IllegalArgumentException(
"Component cannot be added inside it's own content");
}
if (c.getParent() != null) {
// If the component already has a parent, try to remove it
AbstractSingleComponentContainer.removeFromParent(c);
}
c.setParent(this);
fireComponentAttachEvent(c);
markAsDirty();
}
If you're in debug mode, you can somewhat see an image of the composition tree in your browser by adding ?debug to your URL, something like http://localhost:8080/?debug
Well, it looks like I may have solved it.
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
public class MyClass extends Panel {
TextField myField = new TextField();
HorizontalLayout hLayout = new HorizontalLayout();
VerticalLayout vLayout = new VerticalLayout();
Button button = new Button( "Press Me" );
public MyClass() {
super();
applySettings();
}
private void applySettings() {
button.addClickListener(new ClickListener() {
#Override
public void buttonClick(Button.ClickEvent event) {
vLayout.removeAllComponents(); // this is optional
hLayout.addComponent( myField );
setContent( hLayout );
}
});
vLayout.addComponents( myField, button );
this.setContent( vLayout );
}
}
If I don't add myField in the layout constructors, but add it later in the code, it seems to work.
UPDATE
After more testing it seems whichever layout LAST called addComponent() for a given field, THAT layout gets the handle to that field. This behavior seems odd and if someone could explain why this is? That would be enlightening.

How to create a drop down list on right click in GWT

I am creating a Dropdown list which should have CREATE, DELETE, SUBMIT for a particular row in a table. Can someone help me how to create one in GWT.
table.addCellPreviewHandler(new Handler<RequestDto>()
{
#Override
public void onCellPreview(CellPreviewEvent<RequestDto> event)
{
if (event.getNativeEvent().getButton() == NativeEvent.BUTTON_RIGHT)
{
MenuBar options = new MenuBar();
MenuBar gwtPop = new MenuBar();
options.addItem("Create", gwtPop);
options.addItem("Submit", gwtPop);
MenuItem Import = new MenuItem(new SafeHtmlBuilder().appendEscaped("Import").toSafeHtml());
Import.setScheduledCommand(new ScheduledCommand()
{
#Override
public void execute()
{
Window.alert("hello");
}
});
final DialogBox menuWrapper = new DialogBox(true);
menuWrapper.add(options);
gwtPop.addItem(Import);
First of all, do not construct your menu inside onCellPreview method. There is no need to build the same widget over and over again on each click.
You can do something like this:
int clickedRow = -1;
...
// build your menu here
// use clickedRow where necessary, for example:
deleteMenuItem.setScheduledCommand(new ScheduledCommand() {
#Override
public void execute() {
Window.alert("hello, I am about to delete row " + clickedRow);
}
});
...
myTable.addCellPreviewHandler(new Handler<MyObject>() {
#Override
public void onCellPreview(CellPreviewEvent<MyObject> event) {
if (event.getNativeEvent().getButton() == NativeEvent.BUTTON_RIGHT) {
event.getNativeEvent().stopPropagation();
clickedRow = event.getIndex();
// show your menu - no need to construct it again
}
}

How to change the main view of a Vaadin 7 application?

I want to write a Vaadin 7 application (see MyVaadinUI below), which asks the user to enter user name and password.
If they are correct, another view (see MainUI below) should appear and take the entire area (replace the login view).
I tried to implement this transition in the method MyVaadinUI.goToMainWindow, but I get the error
java.lang.RuntimeException: Component must be attached to a session when getConnectorId() is called for the first time
at com.vaadin.server.AbstractClientConnector.getConnectorId(AbstractClientConnector.java:417)
at com.vaadin.server.communication.ConnectorHierarchyWriter.write(ConnectorHierarchyWriter.java:67)
at com.vaadin.server.communication.UidlWriter.write(UidlWriter.java:143)
at com.vaadin.server.communication.UidlRequestHandler.writeUidl(UidlRequestHandler.java:149)
at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:97)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:37)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1371)
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:238)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
when I run the application and press the button.
How can I fix it?
#Theme("mytheme")
#SuppressWarnings("serial")
public class MyVaadinUI extends UI
{
private TextField userNameTextField;
private PasswordField passwordTextField;
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = MyVaadinUI.class, widgetset = "ru.mycompany.vaadin.demo.AppWidgetSet")
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
addUserNameTextField(layout);
addPasswordTextField(layout);
addButton(layout, request);
}
private void addPasswordTextField(Layout aLayout) {
passwordTextField = new PasswordField("Пароль:");
aLayout.addComponent(passwordTextField);
}
private void addUserNameTextField(final Layout aLayout) {
userNameTextField = new TextField("Пользователь:");
aLayout.addComponent(userNameTextField);
}
private void addButton(final Layout aParent, final VaadinRequest request) {
final Button button = new Button("Войти");
button.addClickListener(new Button.ClickListener() {
public void buttonClick(Button.ClickEvent event) {
final boolean credentialsCorrect = checkCredentials();
if (credentialsCorrect) {
goToMainWindow(request);
} else {
[...]
}
}
});
aParent.addComponent(button);
}
private void goToMainWindow(final VaadinRequest aRequest) {
final MainUI mainUI = new MainUI();
mainUI.init(aRequest);
setContent(mainUI);
}
}
#Theme("mytheme")
#SuppressWarnings("serial")
public class MainUI extends UI {
#Override
protected void init(final VaadinRequest vaadinRequest) {
final HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
setContent(splitPanel);
splitPanel.setSizeFull();
splitPanel.setSplitPosition(200, Unit.PIXELS);
final String[] tabLabels = new String[] {
"Tree item 1",
"Tree item 2"};
final Tree tree = new Tree();
for (int i=0; i < tabLabels.length; i++)
{
addTreeItem(tree, tabLabels[i]);
}
splitPanel.setFirstComponent(tree);
splitPanel.setSecondComponent(new Label("Test"));
}
private void addTreeItem(final Tree aTree, final String aLabel) {
aTree.addItem(aLabel);
}
}
On the Vaadin forum someone suggested to use the navigator, which solved my problem.
I'd rather think that MainUI should extend HorizontalSplitPanel, not UI. It is strange concept to me to insert one UI into another.
You can use #SpringUI for the main class which extends UI:
#SpringUI
#Theme("mytheme")
#Widgetset("com.MyAppWidgetset")
#PreserveOnRefresh
public class MainUI extends UI {
private static final long serialVersionUID = -8247521108438815011L;
private static Locale locale = VaadinSession.getCurrent().getLocale();
#Autowired
private ToolBoxMessageSource messageSource;
#Autowired
private SpringViewProvider springViewProvider;
public MainUI() {
}
//Initializes navigator with SpringViewProvider and add all existing
//and ui specific assigned views to navigator.
#Override
protected void init(VaadinRequest vaadinRequest) {
Navigator navigator = new Navigator(this, this);
// Adding springViewProvider for spring autowiring
navigator.addProvider(springViewProvider);
// Adding all views for navigation
navigator.addView(LoginView.NAME, LoginView.class);
navigator.addView(MainView.NAME, MainView.class);
navigator.addView(MailToolView.NAME, MailToolView.class);
navigator.addView(AdminView.NAME, AdminView.class);
navigator.addView(EditRecipientView.NAME, EditRecipientView.class);
navigator.addView(EditRecipientsView.NAME, EditRecipientsView.class);
navigator.addView(ServerView.NAME, ServerView.class);
navigator.addView(TestJobView.NAME, TestJobView.class);
navigator.addView("", new LoginView());
navigator.navigateTo(LoginView.NAME);
navigator.setErrorView(LoginView.class);
// security: if user changes view check if the user has the required rights
navigator.addViewChangeListener(new ViewChangeListener() {
private static final long serialVersionUID = 7330051193056583546L;
#Override
public boolean beforeViewChange(ViewChangeEvent event) {
Toolbox toolbox = getSession().getAttribute(Toolbox.class);
if (TbRightManagement.checkAccess(event.getNewView().getClass(), toolbox)) {
return true;
} else {
if (toolbox != null) {
TBNotification.show(messageSource.getMessage("access.denied.title", locale),
messageSource.getMessage("access.denied.no_permissions.msg", locale),
Type.ERROR_MESSAGE);
navigator.navigateTo(MainView.NAME);
return false;
} else {
TBNotification.show(messageSource.getMessage("access.denied.title", locale),
messageSource.getMessage("access.denied.not_loggedin.msg", locale),
Type.ERROR_MESSAGE);
navigator.navigateTo(LoginView.NAME);
return false;
}
}
}
#Override
public void afterViewChange(ViewChangeEvent event) {}
});
}
}
And for the other views, as an example EditRecipientsView should be a #SpringView which extends a Vaadin Designer and implements a Vaadin View.
#SpringView(name = EditRecipientsView.NAME)
#Theme("mytheme")
#TbRight(loggedIn = true, mailTool = true)
public class EditRecipientsView extends RecipientsDesign implements View {
private static final long serialVersionUID = 1L;
public static final String NAME = "editRecipients";
private static Locale locale = VaadinSession.getCurrent().getLocale();
private BeanItemContainer<Recipient> recipientContainer;
private Uploader uploader;
#Autowired
private ToolBoxMessageSource messageSource;
public EditRecipientsView() {
super();
}
//Initializes the ui components of the recipient view.
#PostConstruct
public void init() {
btn_addRecipient.addClickListener(e -> { MainUI.getCurrent().getNavigator().navigateTo(EditRecipientView.NAME);});
}
//Handling data when entering this view.
#Override
public void enter(ViewChangeEvent event) {
if (getSession().getAttribute(UIMailing.class) != null) {
List<Recipient> recipientList = getSession().getAttribute(UIMailing.class).getRecipients();
if (recipientList != null) {
recipientContainer.removeAllItems();
} else {
recipientList = new ArrayList<Recipient>();
}
recipientContainer.addAll(recipientList);
recipient_table.sort(new Object[] {"foreName", "lastName"}, new boolean[] {true, true});
}
}
}

Resources