I have a container component and multiple 'card' child components. In the sling model of the container component i want to obtain a list of card component sling models.
Container component
-card1
-card2
-card3
I want a list of card models to accessible in container component model so that in HTL i can iterate the list and access data of each card. How do i go about achieving this?
Solved! Go to Solution.
Views
Replies
Total Likes
Hi @Zendarkke
If your container resource structure does contain an intermediate node that would in turn contain the card1, card2, card3 and so on, then the solutions you already received describe how you can map the children.
But if it does not, which I believe is your case, then the only thing you can do (as far as I know) is to write a code in your @PostConstruct method, get all the children from the current resource (the container), take only those matching the resourceType of a card and put in a list on the model class.
Not the best, but here is an example:
import java.util.List;
import java.util.Optional;
import javax.annotation.PostConstruct;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.Self;
@Model(adaptables = { Resource.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ContainerComponentModel {
@Self
private Resource container;
private List<Resource> cards;
@PostConstruct
private void init() {
Optional.ofNullable(container)
.map(Resource::getChildren)
.ifPresent(children -> children.forEach(child -> {
if (child.isResourceType("your_card_resource_type")) {
cards.add(child);
}
}));
}
}
Or if you want to complicate things a little more, I found this example also: https://www.jeroendruwe.be/aem-children-sling-model-annotation
HI @Zendarkke
Please check example here : https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/sling-models-adapt-to-grea...
Hey , went through the example , just to clarify by using @ChildResource annotation above a List<childModel> , we should we able to get the list of all child nodes of that type?
From my understanding the @ChildResource annotation will give the mentioned resource only under the parent resource.
Instead we can make a CardModel, then use getter for List<CardModel> in the Container model.
If structure is like this
+Container
+Cards
+ Card1
+ Card2
then you can use
@ChildResource(name = "Cards")
private List<Resource> cardsResources;
This code snippet worked fine until i changed structure of my component
My container component is having a superType of accordion component so node content structure is
+Container
+card1
+card2
model code snippet
@getter
@ChildResource
private List<ChildModel> children;
However here it is failing to fetch child models when in container html write this code ${model.children} , it shows up as empty,any reason as to why this is failing
Hi @Zendarkke
If your container resource structure does contain an intermediate node that would in turn contain the card1, card2, card3 and so on, then the solutions you already received describe how you can map the children.
But if it does not, which I believe is your case, then the only thing you can do (as far as I know) is to write a code in your @PostConstruct method, get all the children from the current resource (the container), take only those matching the resourceType of a card and put in a list on the model class.
Not the best, but here is an example:
import java.util.List;
import java.util.Optional;
import javax.annotation.PostConstruct;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.Self;
@Model(adaptables = { Resource.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ContainerComponentModel {
@Self
private Resource container;
private List<Resource> cards;
@PostConstruct
private void init() {
Optional.ofNullable(container)
.map(Resource::getChildren)
.ifPresent(children -> children.forEach(child -> {
if (child.isResourceType("your_card_resource_type")) {
cards.add(child);
}
}));
}
}
Or if you want to complicate things a little more, I found this example also: https://www.jeroendruwe.be/aem-children-sling-model-annotation
But how do i create the intermediary node? Do i create an intermediary in the container node structure itself so that when i add child nodes its added under the intermediary or should this be dynamic on addition of child nodes?
Hi @Zendarkke
You don't need to create intermediary node. The code @Tethich shared work on that content structure but you can adjust the code to read children content from immediate node as well.
Please check other code references. Also share the content node structure when you author for this container component so we will guide you better.
1. When you already have significant content that has that container-->child structure, I don't think you should actually create an intermediate node. This might be a cumbersome operation, as you will need to write some code to alter all your places in content where you have such container. And more and more questions pop up when you want to do smth like this in general: How do I know I have modified all ? How do I monitor how my alteration goes ? Will there be any performance issues when data is too large ? Will there be any race condition issues when data is nested and I try to commit my changes ? .... and so on...
In this situation, you would need use the solution I proposed.
2. When you have no content (maybe you are in the development phase still), or small content at least, and you afford to make this change, you can add the intermediate node and later use @ChildResource in your model.
It is still in development phase. The node content structure is as below @arunpatidar @Tethich
Container
--child1
--child2
I find the childResources annotation method to be easier but how do i go about making the node structure to have an intermediary node such as below, then i can directly target the intermediary node
Container
--childnodes
--child1
--child2
you can use the code shared by @Tethich , it is traversing the children nodes for 'container' and returning list of type Cards .
Have tried that code?
Container
--child1
--child2
Then, maybe you can try to use Granite Multifield that will add an child items under a parent node.
Thank you @Tethich @arunpatidar @donquixote_dofl for the help.
Views
Likes
Replies