One criticism developers have of JavaServer Faces is that it is
not possible to add arbitrary attributes to the resultant markup.
Problems arise when they wish to add custom attributes specific to
JavaScript frameworks (e.g. dojoType
for the Dojo toolkit)
or HTML 5 attributes (such as data-
or placeholder
.)
However, this is not a technical limitation of the JSF framework; only a limitation of the standard control library.
All discussion and code that follows relates to J2EE 1.4 (Servlet 2.4; JSP 2.0; JSF 1.1.) I'm currently working on a legacy platform.
The attribute tag in JSF
You can already add arbitrary JSF attributes to components using the attribute tag. These end up on the attributes map. However, these will be ignored unless you implement a custom renderer to take advantage of them. They must work round existing property names on the component and result in overly verbose markup:
<x:foo> <f:attribute name="style" value="text: bold;"> <f:attribute name="data-bar-baz" value="#{xxx}"> </x:foo>
JSP tag libraries
Custom JSP tags are generally defined via tag
library descriptors (TLDs.) Tag handlers usually provide a fixed list of
attributes with strong type information. However, JSP 2.0 introduced the
DynamicAttributes
interface; any tag handler that implements it and declares <dynamic-attributes>true</dynamic-attributes>
can handle attributes that aren't explicitly defined.
JSF 1.1 controls that take arbitrary attributes can be created by
extending UIComponentTag
and implementing DynamicAttributes
.
Note that prior to the Unified Expression Language
deferred expressions of the form #{foo}
would always be
strings and the JSF tag was responsible for their evaluation. In JSP 2.1
onwards the container can intervene and convert these to ValueExpression
s.
Containers from different vendors are not consistent in what objects
they will pass if a deferred expression is included in the value of a
dynamic attribute.
Applying this idea
<g:input id="dob" name="dob" jsf-tag="input" jsf-valueChangeListener="#{testValue.change}" jsf-binding="#{components.in}" jsf-in="#{param['dob']}" type="text" placeholder="Type something" jsf-value="#{testValue.foo}" value="#{testValue.foo}" />
In the above control, all attributes are dynamic. The tag handler
will consider anything prefixed with jsf-
to be a JSF
property to be applied to the control. Anything else will be rendered as
a pass-through attribute. The jsf-in
attribute is evaluated
to get the submitted value. Here is the resulant markup:
<input id="dob" placeholder="Type something" name="dob" value="" type="text"></input>
The control not only lets us emit any attribute, it allows more control over the client identifier.
Sample code
A small library implementing this idea is available in a public
Subversion repository. Further documentation can be found in the gurn/doc/gurn.html
file.
Repository:
http://illegalargumentexception.googlecode.com/svn/trunk/code/java/
License: MIT
Library Project: gurn
Test WAR Project: gurn-tests11
No comments:
Post a Comment
All comments are moderated