Dario Viva
Dario Viva

Reputation: 267

Extending Form Layout looks different that inserting Form Layout

the problem

I wanted one of my Vaadin-Components to use a FormLayout. To do this the component extends FormLayout (com.vaadin.flow.component.formlayout.FormLayout). The component extends the class indirectly over an other class (should not really break the behaviour). Strangely it is not working as expected. It shows all the elements in the layout closely side by side, even though the number of columns is defined.

import com.example.application.model.Memory;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.html.Span;

// AbstractPcPartCard extends FormLayout
@Tag("memory-component")
public class MemoryCard extends AbstractPcPartCard {
    private static final long serialVersionUID = -8954098740536795286L;
    Memory pcPart;

    public MemoryCard(Memory pcPart) {
        this.pcPart = pcPart;

        Span name = new Span(pcPart.getName());
        Span price = new Span(this.getPrice());
        Span stock = new Span(this.getStock());
        Span config = new Span(this.getConfiguration());
        Span form = new Span(this.getFormFactor());
        Span frequency = new Span(this.getFrequency());

        setResponsiveSteps(
            new ResponsiveStep("0", 3),
            new ResponsiveStep("1200px", 6));

        add(name, price, stock, config, form, frequency);
        // we should not need to add a layout, because the component itself is the layout.
    }
    // getters
}

Here is what it looks like: everything side by side

hacky solution

It works correctly if I create a new FormLayout in the Component and add it to the Component. So in a way, I now have a FormLayout in a Formlayout. The Component itself does not need to extend FormLayout in this case. Extending Component (com.vaadin.flow.component.formlayout.FormLayout) would be sufficient.

import com.example.application.model.GraphicsCard;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.html.Span;

import java.util.stream.Collectors;

@Tag("graphics-card-component")
public class GraphicsCardCard extends AbstractPcPartCard {
    private static final long serialVersionUID = -5813124388374902829L;

    GraphicsCard pcPart;

    public GraphicsCardCard(GraphicsCard pcPart) {
        this.pcPart = pcPart;

        FormLayout layout = new FormLayout();

        Span name = new Span(pcPart.getName());
        Span price = new Span(this.getPrice());
        Span stock = new Span(this.getStock());
        Span model = new Span(this.getCardModel());
        Span connections = new Span(this.getConnections());
        Span pci = new Span(this.getPciExpressVersion());
        Span cooling = new Span(this.getCoolingSystem());

        layout.add(name, price, stock, model, connections, pci, cooling);
        layout.setColspan(connections, 2);

        layout.setResponsiveSteps(
                new FormLayout.ResponsiveStep("0", 3),
                new FormLayout.ResponsiveStep("1200px", 6));

        // here we add the FormLayout to the FormLayout
        add(layout);
    }
    // getters 
}

This should look like this: inserted form layout

my wish

I think the Component being a FormLayout itself is much more elegant, than creating a component that contains a FormLayout. How can I fix my FormLayout to display the data in columns?

source code

The full source code of an example project can be found on github. github example project The relevant view and components can be found in package: com.example.application.ui.views.partsComponent

the source code contains other views, some of them are problematic too, for example the view using dom-if, to use different template renderers. But this is another question on stack overflow. link to other question

Upvotes: 3

Views: 261

Answers (1)

gruntled
gruntled

Reputation: 448

The CSS defined for the FormLayout targets the tag <vaadin-form-layout>, but you've changed the tag via @Tag("memory-component"). Therefore, you are losing all of the styles.

Here's a working example that illustrates the difference:

@Route
public class TestFormExtendView extends Div {

public TestFormExtendView() {
    JustExtend justExtend = new JustExtend();
    justExtend.add(new Button("Button1"), new Button("Button2"));
    add(justExtend);

    ExtendAndChangeTag extendAndChangeTag = new ExtendAndChangeTag();
    extendAndChangeTag.add(new Button("Button3"), new Button("Button4"));
    add(extendAndChangeTag);
}

public static class JustExtend extends FormLayout {}

@Tag("extend-and-change-tag")
public static class ExtendAndChangeTag extends FormLayout {}

So you can extend the layout, but don't change the tag.

Advice: I've at times built domain specific components by extending Vaadin layouts, but now only do so when I am adding layout generic features. Conversely, I continue to extend non-layout components for domain specific components. I believe that the layouts in particular were designed for composition rather than extension, and that you're better off not fighting against that.

Upvotes: 3

Related Questions