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
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
but i can see individually on page by directly on node of showcase
Solved! Go to Solution.
Views
Replies
Total Likes
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(); }
@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.
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(); }