On 08 August 2005, Pablo Ruggia said:
> 2) Create some components that creates inputs programatically (i know it can
> be done, but not how).
I have succesfully pulled off something like this. It's not too pretty, but
it seems to work. The core is a simple class called UserField that
describes one field of the form that edits a user:
"""
/**
* A single field in the form for editing user properties. A list
* of these describes the core of any user form (account application,
* edit my profile, etc.).
*/
public class UserField
{
/** How values for this field are get/set on some model object */
private String mPropertyName;
/** Should the user be able to supply a value? */
private boolean mVisible = true;
/** Should the user be told that this field is required? */
private boolean mDisplayRequired = false;
/** Should we get Tapestry to automatically enforce that this field is
* required?
*/
private boolean mEnforceRequired = false;
private int mMinimumLength = 0;
private int mMaximumLength = 255;
/** Width of the text entry field in characters; if -1, derive from
mMaximumLength */
private int mFieldWidth = -1;
/** Map from Locale to UserFieldText instance */
private Map mText = new HashMap();
/**
* Should the text in this field be masked as it's entered?
* (ie. is this a password field?)
*/
private boolean mMasked = false;
public UserField( String propertyName )
{
mPropertyName = propertyName;
}
public UserField( String propertyName,
boolean visible,
boolean required,
int minLength,
int maxLength )
{
this( propertyName );
mVisible = visible;
setRequired( required );
mMinimumLength = minLength;
mMaximumLength = maxLength;
}
[...getters and setters omitted...]
"""
Problem #1: this isn't limited to editing user accounts, so calling it
UserField is kind of lame. Problem #2: it doesn't accomodate any HTML
<input> tag other than <input type="text">. That's fine for us right now,
but not enough for the general case.
The Tapestry end is handled by a component called CustomUserField, which
wraps a ValidField component and a UserField instance and does all the magic
to make the UserField instance influence the ValidField component. The
component spec looks like this:
"""
<component-specification
class="...CustomUserField"
allow-body="no"
allow-informal-parameters="no">
<description>
Generates an HTML table row containing a label, input tag, and
field description all derived from a UserField instance.
</description>
<parameter name="model"
type="java.lang.Object"
required="yes"
direction="in"/>
<parameter name="field"
type="....UserField"
required="yes"
direction="in"/>
<bean name="validator"
class="....UserFieldValidator">
<set-property name="field" expression="field"/>
</bean>
<component id="validField" type="ValidField">
<static-binding name="displayName"
value="will-be-overridden-in-component-class"/>
<binding name="validator" expression="beans.validator"/>
<binding name="value" expression="fieldValue"/>
<binding name="size" expression="field.fieldWidth"/>
<binding name="maxlength" expression="field.maximumLength"/>
<binding name="hidden" expression="field.masked"/>
</component>
</component-specification>
"""
Then the fun stuff is in the component class: the render() method uses
getField() to fetch a UserField instance, which then drives how the
component is rendered. E.g. if getField().isRequired(), then print the
string "(required)" with a particular CSS class right after the <input> tag.
(Oh yeah, another simplification: each CustomUserField assumes that it's one
row of a two-column table where column 1 is the field label, column 2 the
field itself plus any help/error text.) The tricky part was binding the
model object's value to the ValidField via the 'fieldValue' component
property:
"""
class CustomUserField extends AbstractComponent
{
...
public Object getFieldValue() throws OgnlException
{
return Ognl.getValue( parsePropertyName(), getModel() );
}
public void setFieldValue( Object value ) throws OgnlException
{
Ognl.setValue( parsePropertyName(), getModel(), value );
}
private Object parsePropertyName()
{
return OgnlUtils.getParsedExpression( getField().getPropertyName() );
}
}
"""
Like I said, it ain't pretty, but it seems to work.
Greg
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]