Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

How to get content of Fragment Reference in my content fragment using sling model?

Avatar

Level 3

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?

NathanVieira_0-1691156072068.png


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();

}

}
1 Accepted Solution

Avatar

Correct answer by
Level 9

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

https://developer.adobe.com/experience-manager/reference-materials/6-4/javadoc/org/apache/sling/api/...

 

or dam resource api similarly

View solution in original post

4 Replies

Avatar

Level 9

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
}

Avatar

Level 3

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.

camera 1

Nome da câmera
       Camera 1
Ativa
       true
Imagem (opcional)
Rodovia1
sentido
       /content/dam/myproject/sentido-camera-1
Sentido (opcional)
Cidade mais próxima
        Cidade Camera 1
Descrição do quilômetro
         km 34 - SP
Coordenadas geográficas (opcional*)
Ordem (crescente)

 

Avatar

Correct answer by
Level 9

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

https://developer.adobe.com/experience-manager/reference-materials/6-4/javadoc/org/apache/sling/api/...

 

or dam resource api similarly

Avatar

Community Advisor

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

 

 


Aanchal Sikka