vaadinmigratevaadin-flowvaadin21

Vaadin 21 flow. How to migrate CustomLayout used to have a panel with border


with vaadin 7 ( we are trying to migrate to v21, very, very, hard) we have this

CustomLayout cl1 = new CustomLayout(new ByteArrayInputStream("<fieldset><legend location='legend'></legend><div location='content'></div></fieldset>".getBytes()));
cl1.setSizeUndefined();
cl1.add(new Label(title), "legend");
cl1.add( panel, "content");

Basically is a panel with border and title-border How we can do this in vaadin flow v21

Thanks in advance


Solution

  • There's a Cookbook recipe that provides an alternative for CustomLayout: https://cookbook.vaadin.com/custom-layout

    Essentially, the CustomLayout replacement class extends Html in a fairly straightforward way. The add method has most of the logic:

    public class CustomLayout extends Html {
        private Map<String, Component> locations = new HashMap<>();
    
        public CustomLayout(String template) {
            super(template);
        }
    
        public CustomLayout(InputStream stream) {
            super(stream);
        }
    
        public void add(Component child, String location) {
            remove(location);
            locations.put(location, child);
    
            // Establish parent-child relationship, but leave DOM attaching to us
            getElement().appendVirtualChild(child.getElement());
    
            // Attach to the specified location in the actual DOM
            getElement().executeJs("this.querySelector('[location=\"'+$0+'\"]').appendChild($1)", location,
                    child.getElement());
    
            // Ensure the element is removed from the DOM when it's detached
            child.addDetachListener(detachEvent -> {
                detachEvent.unregisterListener();
                getElement().executeJs("this.querySelector && this.querySelector('[location=\"'+$0+'\"]').lastChild.remove()", location);
    
                // Also clear the bookkeeping
                locations.remove(location, child);
            });
        }
    
        public void remove(String location) {
            Component oldChild = locations.remove(location);
            if (oldChild != null) {
                remove(oldChild);
            }
        }
    
        public void remove(Component child) {
            getElement().removeVirtualChild(child.getElement());
        }
    }
    

    Note that it's important to do the bookkeeping with the locations Map so that client-side elements get removed too after the parent is detached.