I have a custom component of type 'Content Fragment List' that returns a list of content fragments.
Each content fragment has a data type 'Fragment Reference' that brings another content fragment with fields like Name, Direction, etc. How can I access the values of the content fragment added to my returning list fragment and display these values on the front-end?
I am using the same structure as the core model 'Content Fragment List'.
package com.myproject.core.models.impl;
import java.util.*;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.jcr.Session;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Default;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.adobe.cq.dam.cfm.converter.ContentTypeConverter;
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.wcm.core.components.util.AbstractComponentImpl;
import com.myproject.core.models.ContentFragmentList;
import com.myproject.core.models.DAMContentFragment;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.search.Predicate;
import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;
import com.day.cq.tagging.TagConstants;
import static com.day.cq.dam.api.DamConstants.NT_DAM_ASSET;
@Model(
adaptables = SlingHttpServletRequest.class,
adapters = {
ContentFragmentList.class,
ComponentExporter.class
},
resourceType = {ContentFragmentListImpl.RESOURCE_TYPE_V1,ContentFragmentListImpl.RESOURCE_TYPE_V2}
)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class ContentFragmentListImpl extends AbstractComponentImpl implements ContentFragmentList {
private static final Logger LOG = LoggerFactory.getLogger(ContentFragmentListImpl.class);
public static final String RESOURCE_TYPE_V1 = "core/wcm/components/contentfragmentlist/v1/contentfragmentlist";
public static final String RESOURCE_TYPE_V2 = "core/wcm/components/contentfragmentlist/v2/contentfragmentlist";
public static final String DEFAULT_DAM_PARENT_PATH = "/content/dam";
public static final int DEFAULT_MAX_ITEMS = -1;
@Self(injectionStrategy = InjectionStrategy.REQUIRED)
private SlingHttpServletRequest slingHttpServletRequest;
@Inject
private ContentTypeConverter contentTypeConverter;
@SlingObject
private ResourceResolver resourceResolver;
@ValueMapValue(name = ContentFragmentList.PN_MODEL_PATH, injectionStrategy = InjectionStrategy.OPTIONAL)
@Nullable
private String modelPath;
@ValueMapValue(name = ContentFragmentList.PN_ELEMENT_NAMES, injectionStrategy = InjectionStrategy.OPTIONAL)
@Nullable
private String[] elementNames;
@ValueMapValue(name = ContentFragmentList.PN_TAG_NAMES, injectionStrategy = InjectionStrategy.OPTIONAL)
@Nullable
private String[] tagNames;
@ValueMapValue(name = ContentFragmentList.PN_PARENT_PATH, injectionStrategy = InjectionStrategy.OPTIONAL)
@Nullable
private String parentPath;
@ValueMapValue(name = ContentFragmentList.PN_MAX_ITEMS, injectionStrategy = InjectionStrategy.OPTIONAL)
@Default(intValues = DEFAULT_MAX_ITEMS)
private int maxItems;
@ValueMapValue(name = ContentFragmentList.PN_ORDER_BY, injectionStrategy = InjectionStrategy.OPTIONAL)
@Default(values = JcrConstants.JCR_CREATED)
private String orderBy;
@ValueMapValue(name = ContentFragmentList.PN_SORT_ORDER, injectionStrategy = InjectionStrategy.OPTIONAL)
@Default(values = Predicate.SORT_ASCENDING)
private String sortOrder;
private final List<DAMContentFragment> items = new ArrayList<>();
@PostConstruct
private void initModel() {
// Default path limits search to DAM
if (StringUtils.isEmpty(parentPath)) {
parentPath = DEFAULT_DAM_PARENT_PATH;
}
if (StringUtils.isEmpty(modelPath)) {
LOG.warn("Please provide a model path");
return;
}
Session session = resourceResolver.adaptTo(Session.class);
if (session == null) {
LOG.warn("Session was null therefore no query was executed");
return;
}
QueryBuilder queryBuilder = resourceResolver.adaptTo(QueryBuilder.class);
if (queryBuilder == null) {
LOG.warn("Query builder was null therefore no query was executed");
return;
}
Map<String, String> queryParameterMap = new HashMap<>();
queryParameterMap.put("path", parentPath);
queryParameterMap.put("type", NT_DAM_ASSET);
queryParameterMap.put("p.limit", Integer.toString(maxItems));
queryParameterMap.put("1_property", JcrConstants.JCR_CONTENT + "/data/cq:model");
queryParameterMap.put("1_property.value", modelPath);
if (StringUtils.isNotEmpty(orderBy)) {
queryParameterMap.put("orderby", "@" + orderBy);
if (StringUtils.isNotEmpty(sortOrder)) {
queryParameterMap.put("orderby.sort", sortOrder);
}
}
ArrayList<String> allTags = new ArrayList<>();
if (tagNames != null && tagNames.length > 0) {
allTags.addAll(Arrays.asList(tagNames));
}
if (!allTags.isEmpty()) {
// Check for the taggable mixin
queryParameterMap.put("2_property", JcrConstants.JCR_CONTENT + "/metadata/" + JcrConstants.JCR_MIXINTYPES);
queryParameterMap.put("2_property.value", TagConstants.NT_TAGGABLE);
// Check for the actual tags (by default, tag are or'ed)
queryParameterMap.put("tagid.property", JcrConstants.JCR_CONTENT + "/metadata/cq:tags");
for (int i = 0; i < allTags.size(); i++) {
queryParameterMap.put(String.format("tagid.%d_value", i + 1), allTags.get(i));
}
queryParameterMap.put("tagid.and", "true");
}
PredicateGroup predicateGroup = PredicateGroup.create(queryParameterMap);
Query query = queryBuilder.createQuery(predicateGroup, session);
SearchResult searchResult = query.getResult();
LOG.debug("Query statement: '{}'", searchResult.getQueryStatement());
// Query builder has a leaking resource resolver, so the following work around is required.
ResourceResolver leakingResourceResolver = null;
try {
// Iterate over the hits if you need special information
Iterator<Resource> resourceIterator = searchResult.getResources();
while (resourceIterator.hasNext()) {
Resource resource = resourceIterator.next();
if (leakingResourceResolver == null) {
// Get a reference to QB's leaking resource resolver
leakingResourceResolver = resource.getResourceResolver();
}
DAMContentFragment contentFragmentModel = new DAMContentFragmentImpl(
resource, contentTypeConverter, null, elementNames);
items.add(contentFragmentModel);
}
} finally {
if (leakingResourceResolver != null) {
// Always close the leaking query builder resource resolver
leakingResourceResolver.close();
}
}
}
@NotNull
@Override
public Collection<DAMContentFragment> getListItems() {
return Collections.unmodifiableCollection(items);
}
@NotNull
@Override
public String getExportedType() {
return slingHttpServletRequest.getResource().getResourceType();
}
}
Solved! Go to Solution.
Views
Replies
Total Likes
if resource " /content/dam/myproject/sentido-camera-1" has a value then you should use common resource api to find this resource and take the value from that resource
or dam resource api similarly
as a sample, you can retrieve associated content fragment via path (considering it has been associated as path in another content fragment)
//Get the resource of content fragment as below.
Resource fragmentResource = resourceResolver.getResource("/content/dam/fragments/my-test-fragment");
//Adapt it to a fragment resource
if (fragmentResource != null) {
ContentFragment fragment = fragmentResource.adaptTo(ContentFragment.class);
// the resource is now accessible through the API
}
And how can I access the path of the fragment path of the dynamically inserted content fragment?
The return of the information I have from content fragments is this, where 'sentido' is the label of the fragment reference, and its value is the path of the inserted fragment that I want to access the values such as Name, Direction, etc.
if resource " /content/dam/myproject/sentido-camera-1" has a value then you should use common resource api to find this resource and take the value from that resource
or dam resource api similarly
Hello @NathanVieira
Please refer to the following Blog
https://kiransg.com/2021/11/13/aem-get-linked-content-fragments-content/
It shares a working code where Agents CF is linked to Car CF.
Concept of Synthetic resource is used fetch values of Agents CF via Sling Model
Views
Likes
Replies
Views
Likes
Replies
Views
Likes
Replies