I was reading the JSF implementation <h:form>
rendering. To my surprise, I see that (in Mojarra, MyFaces + Tomahawk), they add a hidden input field on an encodeBegin()
method.
Here is the sample code for FormRenderer
in Mojarra:
@Override
public void encodeBegin(FacesContext context, UIComponent component)
throws IOException {
rendererParamsNotNull(context, component);
if (!shouldEncode(component)) {
return;
}
ResponseWriter writer = context.getResponseWriter();
assert(writer != null);
String clientId = component.getClientId(context);
// since method and action are rendered here they are not added
// to the pass through attributes in Util class.
writer.write('\n');
writer.startElement("form", component);
writer.writeAttribute("id", clientId, "clientId");
writer.writeAttribute("name", clientId, "name");
writer.writeAttribute("method", "post", null);
writer.writeAttribute("action", getActionStr(context), null);
String styleClass =
(String) component.getAttributes().get("styleClass");
if (styleClass != null) {
writer.writeAttribute("class", styleClass, "styleClass");
}
String acceptcharset = (String)
component.getAttributes().get("acceptcharset");
if (acceptcharset != null) {
writer.writeAttribute("accept-charset", acceptcharset,
"acceptcharset");
}
RenderKitUtils.renderPassThruAttributes(context,
writer,
component,
ATTRIBUTES);
writer.writeText("\n", component, null);
// this hidden field will be checked in the decode method to
// determine if this form has been submitted.
writer.startElement("input", component);
writer.writeAttribute("type", "hidden", "type");
writer.writeAttribute("name", clientId,
"clientId");
writer.writeAttribute("value", clientId, "value");
writer.endElement("input");
writer.write('\n');
// Write out special hhidden field for partial submits
String viewId = context.getViewRoot().getViewId();
String actionURL =
context.getApplication().getViewHandler().getActionURL(context, viewId);
ExternalContext externalContext = context.getExternalContext();
String encodedActionURL = externalContext.encodeActionURL(actionURL);
String encodedPartialActionURL = externalContext.encodePartialActionURL(actionURL);
if (encodedPartialActionURL != null) {
if (!encodedPartialActionURL.equals(encodedActionURL)) {
writer.startElement("input", component);
writer.writeAttribute("type", "hidden", "type");
writer.writeAttribute("name", "javax.faces.encodedURL", null);
writer.writeAttribute("value", encodedPartialActionURL, "value");
writer.endElement("input");
writer.write('\n');
}
}
if (!writeStateAtEnd) {
context.getApplication().getViewHandler().writeState(context);
writer.write('\n');
}
}
My Questions:
component.getClientId(context)
, i.e., a UIForm
component? What's the purpose of the hidden field?id
attribute on <h:form>
but you can on MyFaces. How does JSF treat UIForm
in each cases (e.g. when MyFaces has its an explicit provided id
)?enctype
is defaulted to application/x-www-form-urlencoded
. Can it support multipart/form-data
or text/plain
?Thanks
Why is there a hidden input field that gets assigned the id component.getClientId(context), i.e., a UIForm component? What's the purpose of the hidden field?
Look closer at the comment (line numbers are from Mojarra 2.1.19):
153 // this hidden field will be checked in the decode method to
154 // determine if this form has been submitted.
155 writer.startElement("input", component);
156 writer.writeAttribute("type", "hidden", "type");
157 writer.writeAttribute("name", clientId,
158 "clientId");
159 writer.writeAttribute("value", clientId, "value");
160 writer.endElement("input");
161 writer.write('\n');
This is thus been used to determine which form was been submitted. This determination happens in turn in the FormRenderer#decode()
which is invoked when JSF needs to determine the HTTP request parameters during apply request values phase:
96 // Was our form the one that was submitted? If so, we need to set
97 // the indicator accordingly..
98 Map<String, String> requestParameterMap = context.getExternalContext()
99 .getRequestParameterMap();
100 if (requestParameterMap.containsKey(clientId)) {
101 if (logger.isLoggable(Level.FINE)) {
102 logger.log(Level.FINE,
103 "UIForm with client ID {0}, submitted",
104 clientId);
105 }
106 ((UIForm) component).setSubmitted(true);
107 } else {
108 ((UIForm) component).setSubmitted(false);
109 }
In other words, it controls the outcome of UIForm#isSubmitted()
property. It may be useful in the following use cases involving multiple forms in a page:
In Mojarra, you don't have the option to assign your own id attribute on
<h:form>
but you can on MyFaces. How does JSF treatUIForm
in each cases (e.g. when MyFaces has its an explicit provided id)?
I'm not sure what you're talking about. This,
<h:form id="formId">
works fine for me in Mojarra as well.
Mojarra form enctype is defaulted to application/x-www-form-urlencoded. Can it support multipart/form-data or text/plain?
This is as per JSF specification. And yes, you can just use enctype
attribute the usual way.
<h:form enctype="multipart/form-data">
Whether the submit of such a form is properly recognized by JSF, is a second. Until JSF 2.2, JSF doesn't have builtin support for multipart/form-data
. JSF component libraries solve this by supplying a servlet filter along with their file upload components, usually using Apache Commons FileUpload under the covers. JSF 2.2 just delegates straight to new Servlet 3.0 HttpServletRequest#getPart()
API without the need for a servlet filter using a 3rd party API. See also among others How to upload files to server using JSP/Servlet?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With