Purpose:
Provide an abstraction for managing the submission of statically defined HTML Forms.
How to Use (v1.2.2+)
To create a enable the Forms, create a new sling:OsgiConfig a OSGi component configuration:
/apps/myapp/config/com.adobe.acs.commons.forms.impl.FormsRouterImpl
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="sling:OsgiConfig"
suffix="/submit/form"
/>
The property suffix will be used to identify and properly route Forms submissions.
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" jcr:primaryType="sling:OsgiConfig" suffix="/submit/form" /> |
The property suffix will be used to identify and properly route Forms submissions.
The Form API
The Form abstraction is simple development abstraction for transporting data between the browser and AEM. The abstraction is broken into two part:
-
The Form (Form.java) which represents the mutable Form state
-
The FormHelpers (POST-Redirect-GET or Forward-as-GET) which contain the logic for transporting the Form data and re-constituing the Form on the other side of the HTTP Request.
The Form (Form.java) which represents the mutable Form state
The FormHelpers (POST-Redirect-GET or Forward-as-GET) which contain the logic for transporting the Form data and re-constituing the Form on the other side of the HTTP Request.
Limitations
Current limitations of the Forms implmentation include:
-
Only supports transport of text/String-based data (No file uploads)
-
Multiple form parameters by the same name is not supported. A random value will be selected.
-
Multiple forms can exist on a page, however any data in the unsubmitted forms will be lost (unless you’re using XHR POSTs)
Only supports transport of text/String-based data (No file uploads)
Multiple form parameters by the same name is not supported. A random value will be selected.
Multiple forms can exist on a page, however any data in the unsubmitted forms will be lost (unless you’re using XHR POSTs)
The Form
Form is a class that represents HTTP Form submission data, and contains the following data:
-
name: the form’s conceptual name; acts as a UID when multiple forms are on a page (ex. login, registration)
-
data: which holds submitted form data
-
errors: which holds error messaging associated with form field
name: the form’s conceptual name; acts as a UID when multiple forms are on a page (ex. login, registration)
data: which holds submitted form data
errors: which holds error messaging associated with form field
Form Helpers
Generic Form Helper
FormHelpers interact with Form objects, transporting and re-constructing them on either side of the HTTP Request.
Most of the time the “generic” FormHelper is the better choice. This allows for very easy switching betwen the POST-Redirect-Get and Forward-as-Get implementations.
FormHelper formHelper = sling.getService(PostRedirectGetFormHelper.class);
OR
FormHelper formHelper = sling.getService(ForwardAsGetFormHelper.class);
FormHelper formHelper = sling.getService(PostRedirectGetFormHelper.class);
OR
FormHelper formHelper = sling.getService(ForwardAsGetFormHelper.class);
|
Forward-as-GET Form Helper
The Forward Form Helper is used when Forms need to redirect (Forward-as-GET) internally to render end state of forms.
Forward Form Helper requests the target resource as an internal Synthetic GET Request, and passes the Form object as a SlingHttpServletRequest attribute.
Key features/use-cases
-
Form-payload is too large to be transferred via GET Query Params (to render error page)
-
You aren’t uncomfortable exposing for- data as clear text in query params (even though they fall under SSL envelope)
-
You don’t mind resubmitting forms when a user clicked “refresh”
-
Keeps a “clean” address bar in the browser
Form-payload is too large to be transferred via GET Query Params (to render error page)
You aren’t uncomfortable exposing for- data as clear text in query params (even though they fall under SSL envelope)
You don’t mind resubmitting forms when a user clicked “refresh”
Keeps a “clean” address bar in the browser
POST-Redirect-GET Form Helper
The POST-Redirect-GET (PRG) Form Helper is used when Forms need/can redirect externally (302) to re-render a form or success page.
PRG Form Helper requests the target resource as a 302 Redirect, serialized the Form data as JSON and transports the JSON data as GET Query Parameters. This works well when Form data is under ~2000 characters in total.
Key features/use-cases
-
Form-payload is too small-ish (< 2000 chars encoded)
-
You like a clean separation between your GET and POST requests
-
Don’t mind a messy address bar in the browser (errors are returned to form via GET QPs)
Remember: GET Query Parameters are passed WITHIN the HTTPS envelope, so they are not visible on the wire
Form-payload is too small-ish (< 2000 chars encoded)
You like a clean separation between your GET and POST requests
Don’t mind a messy address bar in the browser (errors are returned to form via GET QPs)
Sample Implementation
This example used the PRGFormHelper, however this can easily be swapped out for the ForwardFormHelper;
The normalized FormHelper API that wraps common usecases in .renderForm(..) and .renderOtherForm(...) methods.
Generally these methods can be used, and PostRedirectGetFormHelper.sendRedrect(..) and ForwardAsGetFormHelper.forwardAsGet(..) can be reserved for unusual use-cases where even more control is required.
demo.jsp
Initialize the Form object with the slingRequest.
This will intelligently look for the Form data from POST Parameters, GET Query Parameters, or HttpServletRequest Attributes depending on the context and FormHelper used.
If the request is a “fresh” request to the page, the form and its errors will be empty.
Changing between Form strategies (PRG vs Fwd-as-GET) is as easy as swapping out the FormHelper as shown below.
Also, don’t forget to make them the same in post.POST.jsp;
IMPORTANT: FormHelper Services should be sync’d between the form rendering JSP and the POST handler JSP.
<%
/* FormHelper formHelper = sling.getService(PostRedirectGetFormHelper.class); */
FormHelper formHelper = sling.getService(ForwardAsGetFormHelper.class);
Form form = formHelper.getForm("demo", slingRequest);
%>
<%-- Check if the form has any errors, and display a list of all the error messages --%>
<% if(form.hasErrors()) { %>
<h2 class="alert">Your form has errors!</h2>
<% } %>
Set the form to POST back to the component; use formHelper.getAction(..) to add the suffix that is registered with the POST handler. Defaults to /submit/form – can change via OSGi configuration on:
com.adobe.acs.commons.forms.helpers.impl.PostFormHelperImpl#prop.form-suffix
Optionally pass a second parameter to getAction() to set the selector used to resolve the script for this POST request. If not provided, defaults to “post” (to resolve to post.POST.jsp).
Useful for multi-page form wizards.
<%
/* FormHelper formHelper = sling.getService(PostRedirectGetFormHelper.class); */ FormHelper formHelper = sling.getService(ForwardAsGetFormHelper.class); Form form = formHelper.getForm("demo", slingRequest); %> <%-- Check if the form has any errors, and display a list of all the error messages --%> <% if(form.hasErrors()) { %> <h2 class="alert">Your form has errors!</h2> <% } %> |
Set the form to POST back to the component; use formHelper.getAction(..) to add the suffix that is registered with the POST handler. Defaults to /submit/form – can change via OSGi configuration on:
Example:
<%= formHelper.getAction(currentPage, "step1") %> will be handled by /apps/acme/components/demo/step1.POST.jsp
<form method="post" action="<%= formHelper.getAction(currentPage) %>">
<%= formHelper.getFormInputsHTML(form) %>
<fieldset>
<legend>Form Demo</legend>
<div><%= form.getError("myField") %></div>
<label <%= form.hasError("myField") ? "class=\"error\"" : "" %>>My Field:</label>
<input type="text" name="myField" value="<%= form.get("myField") %>"/>
<input type="submit" value="Submit"/>
</fieldset>
</form>
<%= formHelper.getAction(currentPage, "step1") %> will be handled by /apps/acme/components/demo/step1.POST.jsp
<form method="post" action="<%= formHelper.getAction(currentPage) %>">
<%= formHelper.getFormInputsHTML(form) %> <fieldset> <legend>Form Demo</legend> <div><%= form.getError("myField") %></div> <label <%= form.hasError("myField") ? "class=\"error\"" : "" %>>My Field:</label> <input type="text" name="myField" value="<%= form.get("myField") %>"/> <input type="submit" value="Submit"/> </fieldset> </form> |
post.POST.jsp
Changing between Form strategies (PostRedirectGet vs ForwardAsGet) is as easy as swapping out the FormHelper as show below. Or for the common case, use generic FormHelper with .renderForm(..)
Choose the return-to-form method based on the Form strategy. You can use PostRedirectGetFormHelper.sendRedirect(..) or ForwardAsGetFormHelper.forwardAsGet(..) variations if the FormHelper.renderForm(..) variations are sufficient (renderForm covers the 80% usecase)
You’ll want to match currentPage/resource/path up to form.getAction(..) in demo.jsp
<%
// PostRedirectGetFormHelper formHelper = sling.getService(ForwardAsGetFormHelper.class);
// ForwardAsGetFormHelper formHelper = sling.getService(ForwardAsGetFormHelper.class);
// FormHelper formHelper = sling.getService(PostRedirectGetFormHelper.class);
FormHelper formHelper = sling.getService(ForwardAsGetFormHelper.class);
// Get the Form
Form form = formHelper.getForm("demo", slingRequest);
// Validation should be moved to a supporting OSGi Service - placement only for illustration
if(form.get("myField") == null || form.get("myField").length() < 10) {
form.setError("myField", "What kind of answer is: " + form.get("myField"));
}
if(form.hasErrors()) {
formHelper.renderForm(form, currentPage, slingRequest, slingResponse);
} else {
// Save the data; or whatever you want
slingResponse.sendRedirect("/content/success.html");
}
%>
Ref: http://adobe-consulting-services.github.io/acs-aem-commons/features/forms.html
<%
// PostRedirectGetFormHelper formHelper = sling.getService(ForwardAsGetFormHelper.class); // ForwardAsGetFormHelper formHelper = sling.getService(ForwardAsGetFormHelper.class); // FormHelper formHelper = sling.getService(PostRedirectGetFormHelper.class); FormHelper formHelper = sling.getService(ForwardAsGetFormHelper.class); // Get the Form Form form = formHelper.getForm("demo", slingRequest); // Validation should be moved to a supporting OSGi Service - placement only for illustration if(form.get("myField") == null || form.get("myField").length() < 10) { form.setError("myField", "What kind of answer is: " + form.get("myField")); } if(form.hasErrors()) { formHelper.renderForm(form, currentPage, slingRequest, slingResponse); } else { // Save the data; or whatever you want slingResponse.sendRedirect("/content/success.html"); } %> |
Nhận xét
Đăng nhận xét