Dario Viva
Dario Viva

Reputation: 267

Use multiple Templates in Vaadin Grid

I want to display different Types of Objects (same supertype) in the same Grid. I want them rendered as Cards, with the help of Template Renderer. Suppose I want to build a webshop for PC-parts. I would have an abstract Class AbstractPcPart.

public abstract class AbstractPcPart {
    private Price price;
    private String name;
    private Int stockQuantity;
    // getters and setters
}

Now I want to have different Parts with different Fields.

public class GraphicsCard extends AbstractPcPart {
    private List<Connector> connections;
    private CoolingSystem coolingSystem;
    private int PciExpressVersion;
    private String cardModel;
    // getters and setters
}
public class Memory extends AbstractPcPart {
    private MemoryConfiguration configuration;
    private String formFactor;
    private int frequency;
    // getters and setters
}

What I already have

I can display one Type in a List. This looks something like this: grid view with memory only Code for this List:

@JsModule("./src/views/parts/card/memory-card.js")
public class PcPartsGrid extends Grid<AbstractPcPart> {
    public PcPartsGrid() {
        super();
        
        addColumn(MemoryCard.getTemplate()
                .withProperty("partCard", MemoryCard::create))
}

public class MemoryCard extends AbstractPcPartCard {
    AbstractPcPart pcPart;
    public MemoryCard (AbstractPcPart pcPart) {
        this.pcPart = pcPart;
    }
    public static MemoryCard create(AbstractPcPart pcPart) {
        return new MemoryCard(pcPart)
    }
    public static TemplateRenderer<AbstractPcPart> getTemplate() {
        return TemplateRenderer.of(
                "<memory-card memory-card='[[item.partCard]]'>"
                + "</memory-card>"
    }

What is the problem?

Now this is fine and all, but when trying to build a grid with different template-renderers this does not work. I tried to add the fallowing Factory.

public class CardFactory {
    public static AbstractPcPart create(AbstractPcPart pcPart) {
        if (pcPart.getClass() == GraphicsCard.class) {
            return GraphicsCardCard.create(pcPart);
        } else if (pcPart.getClass() == Memory.class) {
            return MemoryCard.create(pcPart);
        } else {
            // different Pc Parts
        }
    }

    public static TemplateRenderer<AbstractPcPart> getTemplate(AbstractPcPart pcPart) {
        if (pcPart.getClass() == GraphicsCard.class) {
            return GraphicsCardCard.getTemplate();
        } else if (pcPart.getClass() == Memory.class)  {
            return MemoryCard.getTemplate();
        } else {
            // different Pc Parts
        }
    }
}

And changed the Grid to use this Factory.

@JsModule("./src/views/parts/card/memory-card.js")
@JsModule("./src/views/parts/card/graphics-card-card.js")
public class PcPartsGrid extends Grid<AbstractPcPart> {
    public PcPartsGrid() {
        super();
        
        addColumn(pcPart -> CardFactory.getTemplate(pcPart)
                .withProperty("partCard", CardFactory::create))
}

This is not working as expected, instead of rendering the different Templates in my Grid, it is showing me the references to the template-renderers. template-renderer reference

If this is supposed to work, what am I doing wrong, and what do I need to change, that instead of showing the reference, the template gets rendered?

And if this is expected behaviour, what are viable alternatives?

Edit: I have built an example project and put it on github, for everyone to look at. Example-Project

The Application in the project contains a view vor every different method i used to fill a grid with templates. The fallowing views are present:

Upvotes: 0

Views: 246

Answers (1)

ollitietavainen
ollitietavainen

Reputation: 4275

You can use conditional templates to a degree. The <dom-if if="item.isSomething"> template gets stamped if the isSomething property is truthy. So you can use something like

"<template is='dom-if' if='[[item.first]]'>first template</template>
<template is='dom-if' if='[[item.second]]'>second template</template>
<template is='dom-if' if='[[item.third]]'>third template</template>"

which renders first template if item.first is true and so on. You need to supply the first, second and third properties to the TemplateRenderer with something like .withProperty("first", item -> item.isFirst() ).withProperty("second", item -> item.isSecond()) and so on.

Upvotes: 3

Related Questions