In this post, let us see the approaches to limit the components in container components; in some cases, we may have the use case to limit the number of child components allowed to be added into the container due to the business rules.
Option1 — Limit through FE logic:
Limit the number of components through Front End Javascript; refer to http://mnmaem.blogspot.com/2018/02/aem-parsys-customisation.html for more details on this approach. The challenge of this approach sometime may create incompatibility issues or out-of-sync issues during the AEM level changes.
Option2 — Limit through Edit Config Listeners and Back End Servlet:
In this option, we will use a back-end servlet and an edit config listener(afterchildinsert) to limit the number of components in a container.
- Add the afterchildinsert listener to the component edit config and add the below JavaScript.
function(childEditable) {var path = childEditable.path;
var date = new Date();
var servletURL = '/bin/ComponentLimiterSevlet?' + date.getTime();
var requestData = 'componentPath=' + path;$.ajax({
async: false,
type: 'GET',
url: servletURL,
dataType: 'text',
data: requestData,
success: function(returnData) {if (returnData == 'false') {
var cmp = childEditable.getParent();
cmp.refresh();
showErrorAlert('Cannot drop more component, if you want to add more, please set the Max component allowed bigger.', 'Error');
}}
})function showErrorAlert(message, title) {
var fui = $(window).adaptTo("foundation-ui"),
options = [{
text: "OK",
warning: true
}];
message = message || "Unknown Error";
title = title || "Error";
fui.prompt(title, message, "error", options);
}}
- Enable a maxcomponents property as part of the component design dialog to enable the max allowed components configuration through policy.
- Enable the below servlet that reads the max component property from policy and deletes the added component if the total component count exceeds the max allowed component configured through component policy.
import java.io.IOException;import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Session;
import javax.servlet.Servlet;
import javax.servlet.ServletException;import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.servlets.annotations.SlingServletPaths;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.propertytypes.ServiceDescription;import com.day.cq.wcm.api.policies.ContentPolicy;
import com.day.cq.wcm.api.policies.ContentPolicyManager;@Component(service = { Servlet.class })
@SlingServletPaths("/bin/ComponentLimiterSevlet")
@ServiceDescription("Component Limitor Servlet")
public class ComponentLimitorServlet extends SlingSafeMethodsServlet {private static final long serialVersionUID = 1L;
private String responseMsg = "true";@Override
protected void doGet(final SlingHttpServletRequest req, final SlingHttpServletResponse resp)
throws ServletException, IOException {
try {String currentComponentPath = req.getParameter("componentPath");
String resourcePath = currentComponentPath.substring(0, currentComponentPath.lastIndexOf("/"));ResourceResolver resolver = req.getResourceResolver();Node resourceNode = JcrUtils.getNodeIfExists(resourcePath, resolver.adaptTo(Session.class));if (resourceNode != null) {
int maxComponents = 1;ContentPolicyManager policyManager = resolver.adaptTo(ContentPolicyManager.class);if (policyManager != null) {
ContentPolicy contentPolicy = policyManager.getPolicy(resolver.getResource(resourcePath));if (contentPolicy != null && contentPolicy.getProperties().containsKey("maxComponents")) {
maxComponents = Integer
.parseInt(contentPolicy.getProperties().get("maxComponents", String.class));
}
}int toalComponentCount = 0;
NodeIterator iterator = resourceNode.getNodes();
while (iterator.hasNext()) {
iterator.next();
toalComponentCount++;
}if (toalComponentCount > maxComponents) {
// Gets currently inserted node
Node currentComponentNode = JcrUtils.getNodeIfExists(currentComponentPath,
resolver.adaptTo(Session.class));currentComponentNode.remove();
currentComponentNode.getSession().save();
responseMsg = "false";
} else {
responseMsg = "true";
}
}
} catch (Exception e) {responseMsg = "true";
}
resp.getWriter().print(responseMsg);
}
}
- Configure the max components to the component policy
- Now author will be allowed only to add the max components configured through the policy.
Sample Component — https://github.com/techforum-repo/youttubedata/tree/master/aem/components/containerlimiter
The servlet logic can be extended as required e.g limit adding a specific set of components.
Great solution!
ReplyDelete