Search code examples
vaadinvaadin7

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.


Solution

  • 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

    component hierarchy