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:
- Original View (thats what i had at the beginning, using template renderer for only one version of pcPart)
- View using Cardfactory (this factory is intended to use a different template for each type of pcPart) this shows only the references to the objects instead of the templates (I think this is because I am using a lambda inside the addColumn() method that I inherit from the vaadin Grid)
- View using dom-if elements (this view is using dom-if elements as described in this answer from ollitietavainen, sadly its not working as intended: it’s showing both templates instead of just one)
- View that is not using a template (this is just a simple grid using value providers)
- View that is using a component renderer
- Example-View from Vaadin that also uses a component renderer