Expand my Community achievements bar.

SOLVED

Show the Experience Fragment content in SPA.model.json of Headless mode

Avatar

Level 1

Good morning everyone!

I'm working with AEM in Headless mode and in my SPA I created an Experience Fragment, but when I access the model.json af my SPA it doesn't render the components contained in my Experience Fragmen only the reference that it exists.

Does anyone Know how to make it return all the content contained in the page?

Thanks for help!

1 Accepted Solution

Avatar

Correct answer by
Level 5

hi @Joelcio 

you can update your Experience Fragment model to use the method ModelFactory.exportModel. In my code below, I wanted to expose the content inside the first container of the Experience Fragment, specifically at the path "/master/jcr:content/root."

Here is the output from the /content/myauthorlib/us/en/jcr:content/root/container/container/helloworld.model.json:

{
  "xfContent": {
    "jcr:primaryType": "nt:unstructured",
    "layout": "responsiveGrid",
    "sling:resourceType": "myauthorlib/components/container",
    "separator": {
      "jcr:primaryType": "nt:unstructured",
      "sling:resourceType": "myauthorlib/components/separator"
    },
    "text": {
      "jcr:primaryType": "nt:unstructured",
      "text": "<p>Copyright 2025, My Auhtor Only Lib.&nbsp;All rights reserved.</p>\r\n<p>345 Park Avenue,&nbsp;San Jose, CA 95110-2704, USA</p>\r\n",
      "sling:resourceType": "myauthorlib/components/text",
      "textIsRich": "true"
    }
  }
}

 

Code:

package com.mysite.core.models;

import com.adobe.cq.export.json.ExporterConstants;
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.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import org.apache.sling.models.factory.ModelFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import java.util.Map;

@Model(adaptables = SlingHttpServletRequest.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL,
        resourceType = "myauthorlib/components/helloworld")
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = {"json"})
public class CustomExporterModel {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomExporterModel.class);

    @SlingObject
    private ResourceResolver resourceResolver;

    @OSGiService
    private ModelFactory modelFactory;

    @ValueMapValue
    private String path;

    private Map xfContent;

    @PostConstruct
    protected void init() {
        try {
            if (StringUtils.isNotBlank(path)) {
                // First validate if the path exists
                Resource xfResource = resourceResolver.getResource(path);
                if (xfResource == null) {
                    LOGGER.warn("Experience Fragment resource not found at path: {}", path);
                    return;
                }

                // Log the resource type to verify it's an XF
                LOGGER.debug("XF Resource type: {}", xfResource.getResourceType());

                // Try with different content paths depending on your XF structure
                Resource contentRoot = resourceResolver.getResource(path + "/master/jcr:content/root");
                if (contentRoot == null) {
                    LOGGER.warn("Could not find content root for XF at: {}", path);
                    return;
                }

                // Log found resource to debug
                LOGGER.debug("Found content root at: {}", contentRoot.getPath());
                xfContent = modelFactory.exportModel(contentRoot, "jackson", Map.class, Map.of());

                if (this.xfContent == null) {
                    LOGGER.warn("Container model could not be created from Experience Fragment");
                } else {
                    LOGGER.debug("Container successfully created from Experience Fragment");
                }
            }
        } catch (Exception e) {
            LOGGER.error("Error initializing Experience Fragment container", e);
        }
    }

    public Map<String, Object> getXfContent() {
        return xfContent;
    }
}

 

 

View solution in original post

2 Replies

Avatar

Correct answer by
Level 5

hi @Joelcio 

you can update your Experience Fragment model to use the method ModelFactory.exportModel. In my code below, I wanted to expose the content inside the first container of the Experience Fragment, specifically at the path "/master/jcr:content/root."

Here is the output from the /content/myauthorlib/us/en/jcr:content/root/container/container/helloworld.model.json:

{
  "xfContent": {
    "jcr:primaryType": "nt:unstructured",
    "layout": "responsiveGrid",
    "sling:resourceType": "myauthorlib/components/container",
    "separator": {
      "jcr:primaryType": "nt:unstructured",
      "sling:resourceType": "myauthorlib/components/separator"
    },
    "text": {
      "jcr:primaryType": "nt:unstructured",
      "text": "<p>Copyright 2025, My Auhtor Only Lib.&nbsp;All rights reserved.</p>\r\n<p>345 Park Avenue,&nbsp;San Jose, CA 95110-2704, USA</p>\r\n",
      "sling:resourceType": "myauthorlib/components/text",
      "textIsRich": "true"
    }
  }
}

 

Code:

package com.mysite.core.models;

import com.adobe.cq.export.json.ExporterConstants;
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.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import org.apache.sling.models.factory.ModelFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import java.util.Map;

@Model(adaptables = SlingHttpServletRequest.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL,
        resourceType = "myauthorlib/components/helloworld")
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = {"json"})
public class CustomExporterModel {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomExporterModel.class);

    @SlingObject
    private ResourceResolver resourceResolver;

    @OSGiService
    private ModelFactory modelFactory;

    @ValueMapValue
    private String path;

    private Map xfContent;

    @PostConstruct
    protected void init() {
        try {
            if (StringUtils.isNotBlank(path)) {
                // First validate if the path exists
                Resource xfResource = resourceResolver.getResource(path);
                if (xfResource == null) {
                    LOGGER.warn("Experience Fragment resource not found at path: {}", path);
                    return;
                }

                // Log the resource type to verify it's an XF
                LOGGER.debug("XF Resource type: {}", xfResource.getResourceType());

                // Try with different content paths depending on your XF structure
                Resource contentRoot = resourceResolver.getResource(path + "/master/jcr:content/root");
                if (contentRoot == null) {
                    LOGGER.warn("Could not find content root for XF at: {}", path);
                    return;
                }

                // Log found resource to debug
                LOGGER.debug("Found content root at: {}", contentRoot.getPath());
                xfContent = modelFactory.exportModel(contentRoot, "jackson", Map.class, Map.of());

                if (this.xfContent == null) {
                    LOGGER.warn("Container model could not be created from Experience Fragment");
                } else {
                    LOGGER.debug("Container successfully created from Experience Fragment");
                }
            }
        } catch (Exception e) {
            LOGGER.error("Error initializing Experience Fragment container", e);
        }
    }

    public Map<String, Object> getXfContent() {
        return xfContent;
    }
}

 

 

Avatar

Level 1

Hi @giuseppebag

 

Thanks for your feedback, your solution it worked perfectly.