Expand my Community achievements bar.

Guidelines for the Responsible Use of Generative AI in the Experience Cloud Community.
SOLVED

Component node json not appearing in page json, Issue with exporter for react approach

Avatar

Level 4

I have a requirement like, There is container "showcase-collection" inside the container i have showcase component i want to expose "showcase" node json on page and 

I'm Using @exporter for React json approach the component node structure on crxde page

 

keshava219_1-1653888841879.png

But while im calling on page level all components i cant see "showcase" only showcase-collection 

there is no child nodes its showing under this container like:

 

http://localhost:4502/content/xyz/abc/en/bb-ss-ss.model.json

keshava219_2-1653889311577.png

but i can see individually on page by directly on node of showcase 

http://localhost:4502/content/xyz/en/jcr:content/root/mainresponsivegrid/responsivegrid/showcase_col...

keshava219_3-1653889427502.png

 

 

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hi,

Have you added the component at /ui.frontend/src/components/import-components.js for rendering and for child node collection you need to add a class like below

This examples are for card container(responsivegrid) type component.

Note : The code is not production ready

 

package com.community.aemlab.spa.core.models.impl;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import javax.inject.Inject;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
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.Source;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import org.apache.sling.models.factory.ModelFactory;

import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.export.json.SlingModelFilter;
import com.adobe.cq.wcm.core.components.models.Container;
import com.adobe.cq.wcm.core.components.models.ListItem;
import com.community.aemlab.spa.core.models.CustomGrid;
import com.day.cq.wcm.api.TemplatedResource;
import com.day.cq.wcm.api.components.ComponentManager;
import com.drew.lang.annotations.NotNull;

@Model(adaptables = SlingHttpServletRequest.class, adapters = { CustomGrid.class,
		ComponentExporter.class }, resourceType = CustomGridImpl.RESOURCE_TYPE, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class CustomGridImpl implements CustomGrid, Container {

	static final String RESOURCE_TYPE = "aemlab-spa/components/custom/customgrid";

	@Self
	private SlingHttpServletRequest request;

	@Inject @Source("script-bindings")
	Resource resource;

	@ValueMapValue
	private String gridLayout;

	@ValueMapValue
	private String title;

	@ValueMapValue
	private String description;

	@Override
	public String getDescription() {
		return description;
	}

	@Override
	public String getTitle() {
		return title;
	}

	@Override
	public String getGridLayout() {
		return gridLayout;
	}

	@Override
	public String getExportedType() {
		return CustomGridImpl.RESOURCE_TYPE;
	}

	/**
     * The model factory.
     */
    @OSGiService
    protected ModelFactory modelFactory;

    /**
     * The sling model factory service.
     */
    @OSGiService
    protected SlingModelFilter slingModelFilter;

	/**
     * The list of child items.
     */
    protected List<ListItem> items;

    /**
     * The list of child resources that are components.
     */
    protected List<Resource> childComponents;

    /**
     * The child resources to be exported.
     */
    protected List<Resource> filteredChildComponents;

    /**
     * Map of the child items to be exported wherein the key is the child name, and the value is the child model.
     */
    protected Map<String, ? extends ComponentExporter> itemModels;

    /**
     * The name of the child resources in the order they are to be exported.
     */
    private String[] exportedItemsOrder;


	@NotNull
	@Override
	public Map<String, ? extends ComponentExporter> getExportedItems() {
		 if (itemModels == null) {
	            itemModels = getItemModels(request, ComponentExporter.class);
	        }
	        return itemModels;
	}

	@NotNull
	@Override
	public String[] getExportedItemsOrder() {
		if (exportedItemsOrder == null) {
            Map<String, ? extends ComponentExporter> models = getExportedItems();
            if (!models.isEmpty()) {
                exportedItemsOrder = models.keySet().toArray(ArrayUtils.EMPTY_STRING_ARRAY);
            } else {
                exportedItemsOrder = ArrayUtils.EMPTY_STRING_ARRAY;
            }
        }
        return Arrays.copyOf(exportedItemsOrder, exportedItemsOrder.length);
	}

	/**
     * Get the models for the child resources as provided by {@link AbstractContainerImpl#getFilteredChildren()}.
     *
     * @param request The current request.
     * @param modelClass The child model class.
     * @return Map of models wherein the key is the child name, and the value is it's model.
     */
    protected Map<String, ComponentExporter> getItemModels(@NotNull final SlingHttpServletRequest request,
                                                           @NotNull final Class<ComponentExporter> modelClass) {
        Map<String, ComponentExporter> models = new LinkedHashMap<>();
        getFilteredChildren().forEach(child -> {
            ComponentExporter model = modelFactory.getModelFromWrappedRequest(request, child, modelClass);
            if (model != null) {
                models.put(child.getName(), model);
            }
        });
        return models;
    }

    /**
     * Return (and cache) the list of children resources that are components, filtered by the Sling Model Filter. This
     * should only be used for JSON export, for other usages refer to {@link AbstractContainerImpl#getChildren}.
     *
     * @return The list of children resources available for JSON export.
     */
    @NotNull
    protected List<Resource> getFilteredChildren() {
        if (filteredChildComponents == null) {
            filteredChildComponents = new LinkedList<>();
            slingModelFilter.filterChildResources(getChildren())
                .forEach(filteredChildComponents::add);
        }
        return filteredChildComponents;
    }

    /**
     * Return (and cache) the list of children resources that are components
     *
     * @return List of all children resources that are components.
     */
    @NotNull
    protected List<Resource> getChildren() {
        if (childComponents == null) {
            Resource effectiveResource = this.getEffectiveResource();
            childComponents = Optional.ofNullable(request.getResourceResolver().adaptTo(ComponentManager.class))
                .map(componentManager ->
                    StreamSupport.stream(effectiveResource.getChildren().spliterator(), false)
                        .filter(res -> Objects.nonNull(componentManager.getComponentOfResource(res))))
                .orElseGet(Stream::empty)
                .collect(Collectors.toList());
        }
        return childComponents;
    }

    /**
     * Get the effective {@link TemplatedResource} for the current resource.
     *
     * @return The TemplatedResource, or the current resource if it cannot be adapted to a TemplatedResource.
     */
    @NotNull
    protected Resource getEffectiveResource() {
        if (this.resource instanceof TemplatedResource) {
            return this.resource;
        }
        return Optional.ofNullable((Resource)this.resource.adaptTo(TemplatedResource.class))
                .orElse(Optional.ofNullable((Resource)this.request.adaptTo(TemplatedResource.class))
                .orElse(this.resource));
    }

}
package com.community.aemlab.spa.core.models;

import org.osgi.annotation.versioning.ProviderType;

import com.adobe.cq.export.json.ComponentExporter;

@ProviderType
public interface CardItem extends ComponentExporter {

	public LinkModel getCardItemLink();

	public String getCardItemImage();

	public String getCardItemDescription();

	public String getCardItemTitle();

	public String getCardItemPretitle();

}


Arun Patidar

View solution in original post

2 Replies

Avatar

Community Advisor

@keshava219 Per your post, showcase is not direct child of showcase_collection..it has "content" node in between. What is the resourcetype of content node? Do we have model for it? if not, you may have to write some custom logic in showcase_collection resourctype based sling model to pull in child nodes.

Avatar

Correct answer by
Community Advisor

Hi,

Have you added the component at /ui.frontend/src/components/import-components.js for rendering and for child node collection you need to add a class like below

This examples are for card container(responsivegrid) type component.

Note : The code is not production ready

 

package com.community.aemlab.spa.core.models.impl;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import javax.inject.Inject;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
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.Source;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import org.apache.sling.models.factory.ModelFactory;

import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.export.json.SlingModelFilter;
import com.adobe.cq.wcm.core.components.models.Container;
import com.adobe.cq.wcm.core.components.models.ListItem;
import com.community.aemlab.spa.core.models.CustomGrid;
import com.day.cq.wcm.api.TemplatedResource;
import com.day.cq.wcm.api.components.ComponentManager;
import com.drew.lang.annotations.NotNull;

@Model(adaptables = SlingHttpServletRequest.class, adapters = { CustomGrid.class,
		ComponentExporter.class }, resourceType = CustomGridImpl.RESOURCE_TYPE, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class CustomGridImpl implements CustomGrid, Container {

	static final String RESOURCE_TYPE = "aemlab-spa/components/custom/customgrid";

	@Self
	private SlingHttpServletRequest request;

	@Inject @Source("script-bindings")
	Resource resource;

	@ValueMapValue
	private String gridLayout;

	@ValueMapValue
	private String title;

	@ValueMapValue
	private String description;

	@Override
	public String getDescription() {
		return description;
	}

	@Override
	public String getTitle() {
		return title;
	}

	@Override
	public String getGridLayout() {
		return gridLayout;
	}

	@Override
	public String getExportedType() {
		return CustomGridImpl.RESOURCE_TYPE;
	}

	/**
     * The model factory.
     */
    @OSGiService
    protected ModelFactory modelFactory;

    /**
     * The sling model factory service.
     */
    @OSGiService
    protected SlingModelFilter slingModelFilter;

	/**
     * The list of child items.
     */
    protected List<ListItem> items;

    /**
     * The list of child resources that are components.
     */
    protected List<Resource> childComponents;

    /**
     * The child resources to be exported.
     */
    protected List<Resource> filteredChildComponents;

    /**
     * Map of the child items to be exported wherein the key is the child name, and the value is the child model.
     */
    protected Map<String, ? extends ComponentExporter> itemModels;

    /**
     * The name of the child resources in the order they are to be exported.
     */
    private String[] exportedItemsOrder;


	@NotNull
	@Override
	public Map<String, ? extends ComponentExporter> getExportedItems() {
		 if (itemModels == null) {
	            itemModels = getItemModels(request, ComponentExporter.class);
	        }
	        return itemModels;
	}

	@NotNull
	@Override
	public String[] getExportedItemsOrder() {
		if (exportedItemsOrder == null) {
            Map<String, ? extends ComponentExporter> models = getExportedItems();
            if (!models.isEmpty()) {
                exportedItemsOrder = models.keySet().toArray(ArrayUtils.EMPTY_STRING_ARRAY);
            } else {
                exportedItemsOrder = ArrayUtils.EMPTY_STRING_ARRAY;
            }
        }
        return Arrays.copyOf(exportedItemsOrder, exportedItemsOrder.length);
	}

	/**
     * Get the models for the child resources as provided by {@link AbstractContainerImpl#getFilteredChildren()}.
     *
     * @param request The current request.
     * @param modelClass The child model class.
     * @return Map of models wherein the key is the child name, and the value is it's model.
     */
    protected Map<String, ComponentExporter> getItemModels(@NotNull final SlingHttpServletRequest request,
                                                           @NotNull final Class<ComponentExporter> modelClass) {
        Map<String, ComponentExporter> models = new LinkedHashMap<>();
        getFilteredChildren().forEach(child -> {
            ComponentExporter model = modelFactory.getModelFromWrappedRequest(request, child, modelClass);
            if (model != null) {
                models.put(child.getName(), model);
            }
        });
        return models;
    }

    /**
     * Return (and cache) the list of children resources that are components, filtered by the Sling Model Filter. This
     * should only be used for JSON export, for other usages refer to {@link AbstractContainerImpl#getChildren}.
     *
     * @return The list of children resources available for JSON export.
     */
    @NotNull
    protected List<Resource> getFilteredChildren() {
        if (filteredChildComponents == null) {
            filteredChildComponents = new LinkedList<>();
            slingModelFilter.filterChildResources(getChildren())
                .forEach(filteredChildComponents::add);
        }
        return filteredChildComponents;
    }

    /**
     * Return (and cache) the list of children resources that are components
     *
     * @return List of all children resources that are components.
     */
    @NotNull
    protected List<Resource> getChildren() {
        if (childComponents == null) {
            Resource effectiveResource = this.getEffectiveResource();
            childComponents = Optional.ofNullable(request.getResourceResolver().adaptTo(ComponentManager.class))
                .map(componentManager ->
                    StreamSupport.stream(effectiveResource.getChildren().spliterator(), false)
                        .filter(res -> Objects.nonNull(componentManager.getComponentOfResource(res))))
                .orElseGet(Stream::empty)
                .collect(Collectors.toList());
        }
        return childComponents;
    }

    /**
     * Get the effective {@link TemplatedResource} for the current resource.
     *
     * @return The TemplatedResource, or the current resource if it cannot be adapted to a TemplatedResource.
     */
    @NotNull
    protected Resource getEffectiveResource() {
        if (this.resource instanceof TemplatedResource) {
            return this.resource;
        }
        return Optional.ofNullable((Resource)this.resource.adaptTo(TemplatedResource.class))
                .orElse(Optional.ofNullable((Resource)this.request.adaptTo(TemplatedResource.class))
                .orElse(this.resource));
    }

}
package com.community.aemlab.spa.core.models;

import org.osgi.annotation.versioning.ProviderType;

import com.adobe.cq.export.json.ComponentExporter;

@ProviderType
public interface CardItem extends ComponentExporter {

	public LinkModel getCardItemLink();

	public String getCardItemImage();

	public String getCardItemDescription();

	public String getCardItemTitle();

	public String getCardItemPretitle();

}


Arun Patidar