DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Securing Your Software Supply Chain with JFrog and Azure
Register Today

Trending

  • How To Use Git Cherry-Pick to Apply Selected Commits
  • How to Use an Anti-Corruption Layer Pattern for Improved Microservices Communication
  • From CPU to Memory: Techniques for Tracking Resource Consumption Over Time
  • How AI Will Change Agile Project Management

Trending

  • How To Use Git Cherry-Pick to Apply Selected Commits
  • How to Use an Anti-Corruption Layer Pattern for Improved Microservices Communication
  • From CPU to Memory: Techniques for Tracking Resource Consumption Over Time
  • How AI Will Change Agile Project Management
  1. DZone
  2. Coding
  3. JavaScript
  4. A Simpler Select for Tapestry

A Simpler Select for Tapestry

Taha Siddiqi user avatar by
Taha Siddiqi
·
Jun. 07, 11 · Interview
Like (0)
Save
Tweet
Share
6.07K Views

Join the DZone community and get the full member experience.

Join For Free

After writing my last post, Howard came up with a better idea. Why to stick to only one implementation of Select ? If we need a simpler Select, why not create a simpler one. So, I came with a simple implementation!!

I have not fully tested it (something for next weekend), but it should work as it is mostly copied from the original Select component.

Usage

The usage is quite similar to the one suggested by Inge.

<select t:type='simpleSelect' t:value='user' t:items='users' t:label='name'
t:key='id'/>

label can also be an expression like #{name} (#{address}). It uses '#' instead of '$' as '${}' expressions in a template are resolved by Tapestry and result is passed to the component instead of the actual expression.

How it works

@SupportsInformalParameters
@Events({ EventConstants.VALIDATE,
EventConstants.VALUE_CHANGED + " when 'zone' parameter is 'bound'" })
public class SimpleSelect extends AbstractField {
public static final String CHANGE_EVENT = "change";

@Parameter(required = true, allowNull = false)
private List<?> items;

@Parameter(defaultPrefix = BindingConstants.LITERAL, allowNull = false)
private String label;

@Parameter(defaultPrefix = BindingConstants.LITERAL, allowNull = false)
private String key;

@Parameter(autoconnect = true, required = true)
private Object value;

@Parameter(value = "auto", defaultPrefix = BindingConstants.LITERAL)
private BlankOption blankOption;

@Parameter(defaultPrefix = BindingConstants.LITERAL)
private String blankLabel;

@Parameter(defaultPrefix = BindingConstants.VALIDATE)
private FieldValidator<Object> validate;

@Parameter(defaultPrefix = BindingConstants.LITERAL)
private String zone;

@Inject
private Request request;

@Inject
private ComponentResources resources;

@Inject
private ComponentDefaultProvider defaultProvider;

@Environmental
private ValidationTracker tracker;

@Inject
private PropertyAccess propertyAccess;

@Inject
private TypeCoercer typeCoercer;

@Inject
private FieldValidationSupport fieldValidationSupport;

@Inject
private JavaScriptSupport javaScriptSupport;

@SuppressWarnings("unused")
@Mixin
private RenderDisabled renderDisabled;

private Map<String, PropertyAdapter> adapterMap;

private final static Pattern PROPERTY_PATTERN = Pattern.compile("#\\{([\\w.$_]+)\\}");

@Override
protected void processSubmission(String elementName) {
String submittedValue = request.getParameter(elementName);
tracker.recordInput(this, submittedValue);

Object selectedValue = toValue(submittedValue);
putPropertyNameIntoBeanValidationContext("value");

try {
fieldValidationSupport.validate(selectedValue, resources, validate);
value = selectedValue;
} catch (ValidationException ex) {
tracker.recordError(this, ex.getMessage());
}

removePropertyNameFromBeanValidationContext();
}

private Object toValue(String submittedValue) {
if (InternalUtils.isBlank(submittedValue)) {
return null;
} else {
Object submittedKey = typeCoercer.coerce(submittedValue, getPropertyType(key));

for (Object item : items) {
Object itemKey = getPropertyValue(item, key);
if (itemKey.equals(submittedKey)) {
return item;
}
}
return null;
}
}

Object onChange(@RequestParameter(value = "t:selectvalue", allowBlank = true)
final String selectValue){
final Object newValue = toValue(selectValue);
CaptureResultCallback<Object> callback = new CaptureResultCallback<Object>();
this.resources.triggerEvent(EventConstants.VALUE_CHANGED, new Object[]
{ newValue }, callback);
this.value = newValue;
return callback.getResult();
}

void beginRender(MarkupWriter writer) {
writer.element("select", "id", getClientId(), "name", getControlName());
putPropertyNameIntoBeanValidationContext("value");
validate.render(writer);
removePropertyNameFromBeanValidationContext();

resources.renderInformalParameters(writer);
decorateInsideField();
if (zone != null) {
Link link = resources.createEventLink(CHANGE_EVENT);
JSONObject spec = new JSONObject("selectId", getClientId(),
"zoneId", zone, "url", link.toURI());
javaScriptSupport.addInitializerCall("linkSelectToZone", spec);
}
}

void afterRender(MarkupWriter writer) {
writer.end();
}

@BeforeRenderTemplate
void options(MarkupWriter writer) {
if (showBlankOption()) {
writer.element("option", "value", "");
writer.write(blankLabel);
writer.end();
}

for (Object item : items) {
writer.element("option", "value", getPropertyValue(item, key));

if (value != null && getPropertyValue(key).equals(getPropertyValue(item, key))) {
writer.attributes("selected", "selected");
}
writer.write(getLabel(item));
writer.end();
}
}

private String getLabel(Object item) {
if (label.contains("#")) {
if (adapterMap == null) {
adapterMap = new HashMap<String, PropertyAdapter>();
Matcher matcher = PROPERTY_PATTERN.matcher(label);
while (matcher.find()) {
adapterMap.put(
matcher.group(0),
propertyAccess.getAdapter(resources.getBoundType("value")).
getPropertyAdapter(matcher.group(1)));
}
}

String text = this.label;
for (String key : adapterMap.keySet()) {
String value = adapterMap.get(key) == null ? ""
: adapterMap.get(key).get(item).toString();
text = text.replace(key, value);
}
return text;
} else {
Object propertyValue = getPropertyValue(item, label);
if(propertyValue == null){
return "";
}else {
return propertyValue.toString();
}
}
}

private boolean showBlankOption() {
switch (blankOption) {
case ALWAYS:
return true;

case NEVER:
return false;

default:
return !isRequired();
}
}

String defaultBlankLabel() {
Messages containerMessages = resources.getContainerMessages();
String key = resources.getId() + "-blanklabel";
if (containerMessages.contains(key)) {
return containerMessages.get(key);
}
return null;
}

Binding defaultValidate() {
return defaultProvider.defaultValidatorBinding("value", resources);
}

private Object getPropertyValue(String property) {
return getPropertyValue(value, property);
}

private Object getPropertyValue(Object object, String property) {
if (object == null) {
return null;
}
return propertyAccess.getAdapter(object).getPropertyAdapter(property).
get(object);
}

private Class<?> getPropertyType(String property) {
return propertyAccess.getAdapter(resources.getBoundType("value")).
getPropertyAdapter(property).getType();
}

}

This is mostly the same as the original Select component but instead of using a SelectModel it uses a List and instead of using a ValueEncoder, it relies on the TypeCoercer service for convertion between the client submitted value(String) and the item’s key.

There are two important changes.

  1. Line 85-92 : In order to get the submitted value, we convert the request parameter corresponding to this component to the item’s key using TypeCoercer service and then search through the list for an item with the same key. (Remember the key value has to be unique for each item)
  2. Line 126-144: Here we add a blank option, based on the blankOption parameter and blankLabel parameter. We then add an option tag for each item. The value for each option is obtained after converting its key to String. The content of each option is the resolved label expression.

 

From http://tawus.wordpress.com/2011/06/06/a-simpler-select-for-tapestry/

Label Template Blank (solution) POST (HTTP) Strings Convert (command) Requests

Opinions expressed by DZone contributors are their own.

Trending

  • How To Use Git Cherry-Pick to Apply Selected Commits
  • How to Use an Anti-Corruption Layer Pattern for Improved Microservices Communication
  • From CPU to Memory: Techniques for Tracking Resource Consumption Over Time
  • How AI Will Change Agile Project Management

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: