Form Core Component submission using Custom Action Type | Community
Skip to main content
rsl_lucky
Level 4
January 24, 2022
Solved

Form Core Component submission using Custom Action Type

  • January 24, 2022
  • 2 replies
  • 4978 views

Hi All,

 

Building a Form component by using Form core components. Added Custom Action type in drop down "Custom Action Call " of Form Core container proxy. Now on selection of above custom action in Container component & while Form submission need to call Service/Servlet the back-end for logic execution how to achieve what changes are needed. Any pointers around this on how to & where changes are needed.

Best answer by lukasz-m

Hi lukaszm, 

Yes could find the updates in log file now, issue with my Service which got resolved. In case to call Servlet in above case instead of Service how can we ? Also any thought's how can we apply styles to each field as they are form core components.


Hi @rsl_lucky, using servlet will be much more complicated due to the way how form component has been design. But of course it is possible. It can be done like this:

You will need to create your own Form container component that will extend /apps/core/wcm/components/form/container/v2/container and do some modification in container.html, e.g.

<!--/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ~ Copyright 2016 Adobe
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/-->
<form data-sly-use.container="com.adobe.cq.wcm.core.components.models.form.Container"
      data-sly-use.grid="com.day.cq.wcm.foundation.model.responsivegrid.ResponsiveGrid"
      method="${container.method}" action="${container.action @ addSelectors='formHandler'}" id="${container.id}" name="${container.name}"
      enctype="${container.enctype}"
      class="cmp-form ${grid.cssClass}">
    <div data-sly-test="${container.errorMessages}"
         data-sly-list.item="${container.errorMessages}"
         class="cmp-form-error">
        <p class="cmp-form-error__item">${item}</p>
    </div>
    <input type="hidden" name=":formstart" value="${resource.path}"/>
    <input type="hidden" name="_charset_" value="utf-8"/>
    <input data-sly-test="${container.redirect}" type="hidden" name=":redirect" value="${container.redirect @ extension='html'}"/>
    <sly data-sly-repeat.paragraph="${grid.paragraphs}"
         data-sly-resource="${paragraph.path @ resourceType=paragraph.resourceType, decorationTagName='div', cssClassName=paragraph.cssClass}"></sly>
    <sly data-sly-resource="${resource.path @ resourceType=container.resourceTypeForDropArea, appendPath='/*', decorationTagName='div', cssClassName='new section aem-Grid-newComponent'}"
         data-sly-test="${wcmmode.edit || wcmmode.preview}"></sly>
</form>

The change that has been done is formHandler selector has been added, so it will be included in link set inside action attribute.

Next we have servlet that will consume the request:

package com.mysite.core.servlets;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.osgi.service.component.annotations.Component;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;

@Component(service = Servlet.class, property = {
    "sling.servlet.methods=" + HttpConstants.METHOD_POST,
    "sling.servlet.resourceTypes=sling/servlet/default",
    "sling.servlet.selectors=formHandler",
    "sling.servlet.extensions=html"
})
public class MyFormServlet  extends SlingAllMethodsServlet {

    @Override
    protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("Handling form request via servlet");
    }
}

and the last thing, you need to disable com.adobe.cq.wcm.core.components.internal.servlets.CoreFormHandlingServlet OSGi component - you can sue component disbaler functinality form ACS Commons. The main reason for that is the fact that CoreFormHandlingServlet is servlet and filter so it is run in filter chain for every request.

I think that the previous solution is a bit better, because you do not need to change what you are getting out of the box. Of course running service from jsp is not a nice solution but I think as long you will keep your business logic in some java class/service this could be acceptable.

2 replies

lukasz-m
Community Advisor
Community Advisor
January 24, 2022

Hi @rsl_lucky, please find below very simple implementation of custom action that is handled by OSGi service.

CRX structure:

Code for above structure:

 

<customAction jcr:primaryType="sling:Folder" jcr:title="Custom action" sling:resourceType="foundation/components/form/action"> <cq:dialog jcr:primaryType="nt:unstructured" jcr:title="Form Container" sling:resourceType="granite/ui/components/coral/foundation/container"> <granite:data jcr:primaryType="nt:unstructured" showhidetargetvalue="my-app/components/form/actions/customAction" usesRedirect="true"/> </cq:dialog> </customAction>

 

post.POST.jsp

 

<%-- Custom Action example --%><% %><%@include file="/libs/foundation/global.jsp"%><% %><%@page session="false" %><% %><%@page import="com.myapp.MySampleService"%><% %><% final MySampleService mySampleService = sling.getService(MySampleService.class); mySampleService.handleFormRequest(slingRequest, slingResponse); %>

 

OSGi service:

 

import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.osgi.service.component.annotations.Component; @Component(service = MySampleService.class) public class MySampleService { public void handleFormRequest(final SlingHttpServletRequest request, final SlingHttpServletResponse response) { System.out.println("Custom form action"); // place for your code } }

 

In general post.POST.jsp is handling the request, from this place you can run any logic you like.

rsl_lucky
rsl_luckyAuthor
Level 4
January 25, 2022

Hi lukaszm 

Implemented the same code for testing the approach but service was not getting called. Let me try check the issue at service end and is their any other approach to implement to call servlet.

lukasz-m
Community Advisor
Community Advisor
January 25, 2022

Hi @rsl_lucky, I have checked it one more time and it is working fine on my AEM 6.5.11 - service implementation is called. Do you see any errors in the log, also did you checked stdout.log - this is where the output from above sample code will go.

rahulp76079001
Level 2
March 6, 2025

This can be done by simply implementing FormSubmitActionService interface.

import com.adobe.aemds.guide.service.FormSubmitActionService; public class CustomSubmitAction implements FormSubmitActionService

You need to set a variable named as serviceName, which is required to be mapped with customAction component,

 

 also same will be returned from 

@9944223 public String getServiceName() { return serviceName; }