Hello Community members,
This new look feels great btw. Congrats to Adobe.
My question is regarding sling model for a resource that I want to adapt. I understand that resource to be adapted is able to inject a list of grandchildren. But is there a way to exclude or filter out some values based on a condition. Like example below. How do I write a Sling model that returns only grandchild nodes that have prop1 value = male.
|-- myresource(to be adapted)
|-- children
|-- grandchild1 [prop1(name=gchildtype, value=male), prop2, prop3 and so on]
|-- grandchild2 [prop1(name=gchildtype, value=female), prop2, prop3 and so on]
|-- grandchild3 [prop1(name=gchildtype, value=male), prop2, prop3 and so on]
|-- grandchild4 [prop1(name=gchildtype, value=female), prop2, prop3 and so on]
@Model(adaptables = Resource.class)
public class MaleMembers {
@Inject
private List<GrandChildClass> children;
public List<GrandChildClass> getChildren() {
return children;
}
}
The above model will hold a list of all grandchildren. But how to get a partial list based on some condition like nodetype or any properties value, in this case gchildtype.
May be something like below could have been great:
@Inject @Filtered("gchildtype"="male")
private List<GrandChildClass> children;
Or May be in the GrandChildClass model, we could do something like:
@Model(adaptables = Resource.class)
public class MaleGrandChildClass {
@Inject @AdaptOnly("gchildtype"="male")
private String gchildtype;
public String getGchildtype() {
return gchildtype;
}
}
This is a great question. I wish we had a good example on this. I will check. We indeed need to expand our Sling Model examples.
Views
Replies
Total Likes
Here is the Sling docs on this subject that may help-- Apache Sling - Sling Models.
In meantime - i am going to code this and what happens.
Views
Replies
Total Likes
I don't see current injectors/annotation can filter the list of grand child resources.
But sounds like what you are trying to do is to adapt your child resource to a list of filtered grand child resources, which can be achieved by creating a custom ChildModel, and then have a method to get a list of filtered grand child resources based on the property value.
or you can create your own injector/annotation if you think that can be reused in multiple places
Views
Replies
Total Likes
I believe there is nothing called native inside the sling model or AEM. You may need to create a custom logic for it. If I were you I would have:
1. Created an OSGI Service which would have a injected a sling model (of your path)
2. A method that could get the node from that path using sling model
3. Method would then filter the result by traversing the node (use List Filters of Java)
4. Return the result.
#3 this method can be more generic with a custom logic to filter on values, parents, siblings, childs etc.
Views
Replies
Total Likes
In this case - @Filter annotation did not filter the list based on the value of the property on the grandchilden nodes. I had to use Java application logic as suggested by navinkaushal
I used this app logic:
private List returnFemale(List list)
{
java.util.Iterator itr = list.iterator();
List newList = new ArrayList();
String myVal ="";
try{
while(itr.hasNext()) {
//Cast to a Resource
Resource myRes = (Resource)itr.next();
Node myNode= myRes.adaptTo(Node.class);
//only keep a node if value is female
myVal = myNode.getProperty("value").getString();
if (myVal.compareTo("female") ==0)
{
newList.add(myNode);
}
}
}
catch(Exception e)
{
e.printStackTrace() ;
}
return newList;
}
The new list now only contains nodes where the value property is female. It works nicely. There are three grandchildren nodes where value is equal to female.
Sometimes when developing in AEM - it is best to use custom Java application logic using given APIs.
Views
Replies
Total Likes
I think in your example you need to implement a PostConstruct, and have the logic in there.
What you can do its just using script bindings, like that in HTL (seems to be legit way to do):
<sly data-sly-use.filteredGrandClindren="${'an.example.FilteredGrandChildren' @ filter='someproperty=somevalue'" />
<!-- use it somehow -->
Keep in mind that filter property here its just a custom one, so you can do it even with two parameters like property and value, who knows what is better!
Alright, so now there is a draft how to use it, but how to implement it? I won't write all class, believe that you can figure out most of placeholders I left you here:
@Model // all those stuff you need to make its model, adaptable should be a Request (fortunately or not)
public class FilteredGrandChildren {
@Self
@Via("resource")
private Resource resource; // so the resource that are you reffering to (lets name it a root)
@Inject
private String filter; // which is provided by script bindings - no worries, Sling should figure out which injector will use
public List<Resource> getFilteredChildren() {
Pair<String, String> splittedFilter = splitFilterToPropertyNameAndValue(filter);
return filter(getChildren(resource), splittedFilter.getLeft(), splittedFilter.getRight());
}
private List<Resource> getChildren(Resource resource) {} // essentially getting all children or grandchildrens, whatever you want
private List<Resource> filter(List<Resource> children, String propertyName, String propertyValue) { } // filtering collection
private Pair<String, String> splitFilterToPropertyNameAndValue(String filter) {} // obviously splitting by '='
Hope that it helps a little. That type of solution can be used across all project IMO and its not tightly coupled to any other model you should have.
Views
Replies
Total Likes
Hello Feike Visser and smacdonald2008, navinkaushal, eddiey39441077, @puradawid .Thanks guys. Really appreciate.
Ofcourse doing an iteration on the list (and explicit filtering) is very obvious. But I want to avoid that as it will consume some extra time. Actually in my code I have already done that. My concern is regarding a huge list. {am i over-concerned here? or is it legit?}
Iterating (and or filtering) would be same as writing a listChildren(). And we would miss all fun and value that the Injects and the Adapts bring to the table. I was looking for a way that Sling could on-its-own (with some flag ofcourse) adapt the resource and inject only desired grandchildren.
I guess there isnt anything available to do that, like an Annotation or an Inject Strategy or something else.
Views
Replies
Total Likes
i have not seen a good working example in the Sling Docs that would filter that list without explicit Java logic. Some say Sling Bindings - but i have not seen an actual example where that would filter the list.
Views
Replies
Total Likes