Tapestry Training -- From The Source

Let me help you get your team up to speed in Tapestry ... fast. Visit howardlewisship.com for details on training, mentoring and support!

Thursday, April 28, 2005

An interesting idea: FieldLabel & ValidField

There's been some talk on the Tapestry developer list about radically reworking Tapestry's validation support (primarily, ValidField, FieldLabel and the helper classes ValidationDelegate and all the IValidator implementations). There's a lot of good reasons to do that ... the validation support in Tapestry is pretty good, but was written largely in 2001 and 2002, with only minor tweaks (such as client side validation) since then. Especially in Picasso, there's a lot of opportunity to improve it.

Until that happens (and based on the amount of movement on this subject, a complete overhaul is not likely to make it into the 4.0 release), people are still depending on the existing validation.

One of the most annoying, if relatively minor, problems with validation is the relationship between FieldLabel and ValidField when rendering, with decorations, inside a complex form (that is, with loops). There gets to be a nasty off-by-one problem, where the FieldLabel is out of sync with the ValidField and the wrong FieldLabel instance (within the enclosing loop) get decorated.

This is because the FieldLabel renders before the ValidField (in most Western language, left-to-right style layouts). I came up with a kind of kludge about how to approach this, where we gimic things to get the ValidField to render before the FieldLabel ... but then defer emitting that output into the response stream until the correct point.

What occurred to me this morning is that, with a modest amount of effort, we could bake this directly into the components That is, the FieldLabel could:

  • Obtain its field (i.e., a IFormComponent instance)
  • Create a nested IMarkupWriter
  • Have the field render into the nested writer
  • Store the writer as an IRequestCycle attribute, using a key that includes the form component's extendedId
  • Do it's own rendering

The ValidField (and all the other IFormComponent implementations) would have to:

  • See if there's a pre-renderered writer IRequestCycle attribute
  • If so: close the writer (which injects the buffered markup into the outer writer) and remove the attribute
  • If not: render normally

It's a bit of work, since it will require updating all the form control components. It's also a chance to get, at least, decoration of all form control components working.

In addition, I believe I'll change the Form component to provide a default IValidationDelegate even when its delegate parameter is not bound ... and change the code inside the various components to expect a non-null delegate from the form.

Finally, I've been thinking that an alternate way to define validators, using a binding prefix, would be useful, something like:

<binding name="validator" value="validator:string,required,minLength=3"/>

3 comments:

MJ said...

Not too long ago, I read your Tapestry in Action book. With all of the changes proposed for Picasso, does it make sense to start creating a website using Tapestry (as described in the book, which I think is version 3.1), or wait for Picasso to be released first? If the latter, will there be an update to the book? I have no clue about exactly what HiveMind is (or is useful for), although I'm sure it's great. I haven't used Spring before either, so I have no similar experience to base an understanding of HiveMind from. I wouldn't mind seeing a HiveMind in Action book, though.

Terry C. Martin said...

I'm extremely new to Tapestry. I bought the book and I'm pretty much LOVING what can be done. It's the front-end solution I've been looking for (and I've been looking for a while, like xmlc & JSF). Anyway, just one thing I don't quite get, and please pardon my insolence, but from what I can see and have read, I'm not very 'onboard' with the validation framework. Can someone write something on why I should use it versus Struts/Jakarta Validator? Not that I'm a huge fan of Jakarta Validator (I've always felt in the back of my mind, there must be a less verbose way to do the same things) but Tapestry's validator doesn't seem to be as full-featured (at least, not without doing a lot of the work myself). For example, at least from reading the book, I see no way to do automatic conditional field validation: like - if passwdcheck was 'checked', then validate 'passwd1' & 'passwd2' fields and make sure they're both equal to each other. Can that be done? I also don't like being made to code the css stuff into the delegate. At least it seems like there should be a utility delegate that someone else already made. I like that I can go that deep if I so choose, but I don't so choose (not yet at least). Is anyone else following me or are these none-issues for everyone else? Thanks for your time. I'll take my answer off the air ;-)

Brian said...

In reply to chuinnim, you can use the Dojo Event System to encapsulate the validation functions rendered by Tapestry.

Check out http://dojotoolkit.org/docs/dojo_event_system.html
and read the description related to the "around" keyword.

I had a simple situation where I wanted number validation on a field only when a checkbox was not selected. My code ended up looking like this:


function checkIntervalRequired(invocation) {
if(dojo.byId("OnlyOnceControl").checked) {
return true;
}
else {
return invocation.proceed();
}
}

dojo.event.connect("around", "validate_inputInterval", "checkIntervalRequired");