I've been thinking a lot about how JavaScript on the client side, and
Tapestry, interact.
I think the current Tapestry approach is somewhat limiting.
I would like to put together a simple client-side event bus, tailored
to Tapestry's useage.
This would be useful for Forms, and would give us more flexibility on
the client side.
There would be some Tapestry-specific events on the bus, such as
"validate this form".
Right now, it would be very, very hard to, say, run all the
validations and update the HTML to display an error message beside
each field (or, alternately, to display error messages at the top of
the form). And clear those error messages as the fields are correct
(or on the next attempted submit). Accomplishing that with an event
bus would be easier (but there's still some unknowns).
On 5/7/05, Numa Schmeder <[EMAIL PROTECTED]> wrote:
> Sorry to respond so late.
> On 5 mai 05, at 19:52, Paul Ferraro wrote:
>
> > Numa Schmeder wrote:
> >
> >> Hello,
> >>
> >> Thanks to all for the feedback.
> >> See my comment below:
> >>
> >> On 4 mai 05, at 21:00, Paul Ferraro wrote:
> >>
> >>> Numa Schmeder wrote:
> >>>
> >>>> Hello,
> >>>>
> >>>> I have read the tapestry blog about the new validators, and i find
> >>>> the solution very neet. But i would like to submit an idea that
> >>>> might be not realistic, but that i find nice.
> >>>>
> >>>> - 1 All fields should be validFields with by default no special
> >>>> validation. The question is should a field with an empty input
> >>>> should update it's value as a null value or as an empty String?
> >>>> Actually a textField updates its binding as an empty String if
> >>>> there is no input, this seems to me strange, and maybe we should be
> >>>> able to have the option between empty or null. For example if you
> >>>> use jdo or hibernate and you map your model objects to a tapestry
> >>>> form then all strings will be empty String (not null) and be
> >>>> inserted in the database as an empty varchar and not as a null
> >>>> value. I hope you see my point.
> >>>>
> >>> Currently, the IValidator interface serves triple duty and is
> >>> responsible for:
> >>> 1. Indicating whether a field is required or not, and if so,
> >>> validating that a value was submitted.
> >>> 2. Translating the text submitted with the ValidField to an
> >>> appropriate typed value.
> >>> 3. Performing some validation on either the submitted text, or the
> >>> translated value.
> >>> Consequently there is a lot of duplication of logic across
> >>> validators.
> >>>
> >>> In 4.0, I'm working on decoupling these responsibilities, breaking
> >>> up the IValidator into 3 pieces.
> >>> 1. "required" - a new parameter for most form components, including
> >>> RadioGroup, Select, PropertySelection, Checkbox, TextField,
> >>> TextArea, DatePicker, and Upload. If isRequired() is true (it will
> >>> default to false), and no value (or an empty value) is submitted,
> >>> then a validation error is recorded and rewinding of the component
> >>> is finished.
> >>>
> >>> Text driven fields, including TextField, TextArea, and DatePicker
> >>> will all have 2 additional parameters:
> >>> 2. "translator" - a new Translator interface will be responsible for
> >>> translating the input text into its desired type. Out-of-the-box
> >>> translators will include StringTranslator (includes a property to
> >>> determine whether an empty string will be interpreted as a null),
> >>> DateTranslator, and NumberTranslator (using
> >>> java.text.DecimalFormat). TextArea's translator parameter will
> >>> default to a StringTranslator. DatePicker's translator will default
> >>> to a DateTranslator. Although TextField's translator will default
> >>> to StringTranslator, it value parameter will bind to an Object
> >>> (formerly value was bound to a String) so that it can use any
> >>> translator. If the Translator fails to translate the submitted
> >>> text, then a validation error is recording and rewinding of the
> >>> component is finished.
> >>>
> >> I think that implementing a translator is a great idea, because
> >> many time you need your values displayed differently as the way they
> >> are stored in the model. But maybe the translator needs to be like a
> >> java.text.Format, the only bad things about the Format interface is
> >> that it is not very simple to implement and that is only one way.
> >> Thus using translator that can format data from the model to the view
> >> and then from the view to the model is a great idea, i would see it
> >> like cocoa translators if you know what i mean.
> >>
> > The Translator interface is used for both String to Object translation
> > (rewind) and Object to String translation (render). Both the
> > NumberTranslator and DateTranslator will be java.text.Format-based
> > (using DecimalFormat and SimpleDateFormat, respectively).
> >
> >>> 3. "validators" - (a single Validator or list of Validators) a new
> >>> simplified Validator interface will be responsible for validating
> >>> the translated value (not the submitted text). By making the
> >>> validators fine-grained, and by allowing multiple validators to be
> >>> used per field, we eliminate some more of the redundancy that exists
> >>> currently. Out-of-the-box validators will include StringValidator
> >>> (maxLength, minLength), EmailValidator, RegExValidator,
> >>> EqualsValidator, and ComparableValidator (max, min). If the
> >>> Validator fails to validate the translated value, then a validation
> >>> error is recording and rewinding of the component is finished.
> >>>
> >>> Consequently:
> >>> a. The old IValidator interface can be deprecated.
> >>> b. ValidField can be deprecated since it functionality is completely
> >>> achievable via the beefed up TextField.
> >>>
> >>> In Howard's blog, he suggests a new validator binding:
> >>> <binding name="validator"
> >>> value="validator:string,required,minLength=3"/>
> >>>
> >>> Essentially, this is what I described above (i.e. the 3 validator
> >>> responsibilities) except that it's all smushed into a single
> >>> parameter. I think the smushed representation is too cluttered.
> >>> Especially since the translator part (e.g. string) will use a most
> >>> often use a default value. I sort of like the idea of defining a
> >>> validator inline (e.g. minLength=3), but I think it will get too
> >>> messy and complex, especially when I want to use custom (i.e.
> >>> non-framework) validator implementations.
> >>
> >>
> >> I agree that defining inline validator might not be the best, as
> >> when you want to define a custom validator it will be a completely
> >> different way to put it in the component. I like the method of
> >> Howard because it is convenient for most simple case and that should
> >> be the default. But as Howard said, in Tapestry 4 you can define new
> >> prefix, thus we can define a prefix for simple validation syntax
> >> 'value="validator:string,required,minLength=3"' and a prefix for
> >> backward compatible validator. I think validation rules should not
> >> be tied to a field as in your suggestion, because a validation rule
> >> is tied to the logic of a form and not to the logic of a component,
> >> thus we would need to implement a new mechanism independent of per
> >> component validation but dependant of per form validation. The other
> >> point is that most complex form validation are conditional, not all
> >> validation rule should be interpreted, validation rules should be
> >> interpreted only if a special condition is verified. So maybe using
> >> your proposition of equal/comparable validator we should add a non
> >> mandatory property to the component that would be
> >> 'validatorCondition="myOtherComp.value == true"' if the condition is
> >> not verified then the validator should not display any error or
> >> should not be used.
> >>
> > Can you elaborate on what you mean be per form validation? Why would
> > you not want to associate a validator with a field? Can't cross-field
> > (i.e. per form) validation always be performed on the last field in
> > the validation set?
> > Since "validators" will already be an optional parameter (currently,
> > this is not the case with ValidField), there's no real need for an
> > additional parameter to toggle it (although I admit it might make
> > things easier to read):
> > e.g.
> > <bean name="someValidator" class="..."/>
> > <component id="someField" type="TextField">
> > <!-- ... -->
> > <binding name="validators" value="someCondition ?
> > beans.someValidator : null"/>
> > </component>
> >
> Ok, i see your point, and i must say you convince me. This is a
> clean approach. Does someCondition is evaluated at rewind time ? Most
> often condition will be based on form input. The only point that might
> be complicated is involving javascript validation. This way, it would
> be hard te create javascript validation (i might be mistaken). Or an
> option is that validators would have a method that one could override
> to generate the javascript for this validator. The method would take
> in argument the html field names generated by tapestry and would return
> a javascript snippet with a message. This snippet could then be
> incorporated in a main javascript 'validate_myForm()' function. Maybe
> even better, instead of a function we would define a ".script" file
> with its argument being a list of fields and their type (checkbox,
> textarea, input text etc..), and thus generate a javascript snippet
> that will be added to the main javascript validation function. I don't
> if i am very clear on this one?!
> The only problem with my proposal is then how do you integrate the
> someCondition in the javascript snippet generation as it is decoupled
> from the validator?
>
>
> >>
> >>
> >>>
> >>>> - 3 Multi component validation: I think it is possible to do a
> >>>> multi component validation using the Java Comparable interface, if
> >>>> the component implements the Comparable interface or delegate it to
> >>>> the validator then we could compare components between them an
> >>>> write an expression this way i:
> >>>> Suppose We have a check box, and two text fields component in the
> >>>> page
> >>>> <validationRule>
> >>>> <condition>myCheckbox == true </condition> //condition for this
> >>>> rule to be evaluated
> >>>> <rule> passwd1 != passwd2 </rule> // rule to be evaluated
> >>>> <message>For new customers the password 1 and the password 2 must
> >>>> be the same </message> // validation message to be displayed
> >>>> </validationRule>
> >>>> A special helper object would be used to interpret and verify the
> >>>> rule, the object would read this rule and interpret it as follow,
> >>>> get the value of myCheckbox component and verify if it si true then
> >>>> get the value of passwd1 field and compare it for equality to the
> >>>> value of passwd2. We could use OGNL to do this. OGNL will
> >>>> interpret the ==, <, >, != using compare and equals, the components
> >>>> should override the equal and compare function to forward it to its
> >>>> value, thus calling passwd1 != passwd2 will be transformed in "if
> >>>> (!passwd1.equals(passwd1))" and the equals will be overwritten as
> >>>> follow:
> >>>> public boolean equals(Object other) {
> >>>> if (!(other instanceof IFormComponent)) {
> >>>> throw Exception();
> >>>> }
> >>>> Object thisValue = this.getValue();
> >>>> Object otherValue = other.getValue();
> >>>> return thisValue.equals(otherValue);
> >>>> }
> >>>>
> >>>> The same would happen for the compareTo method, and if the value
> >>>> don't implement comparable then an exception should be thrown. If
> >>>> the value are primitive then we make direct comparison of primitive
> >>>> value.
> >>>>
> >>> This is the intention of the EqualsValidator and ComparableValidator
> >>> mentioned above. For instance, say I have a user registration page
> >>> where I ask the user to enter a password - typically a page will
> >>> show 2 text fields, the second being a "confirmation" that the user
> >>> didn't make a typing mistake when entering their password. In this
> >>> scenario I would use an EqualsValidator to validate the equivalency
> >>> accross fields. It might look roughly like the following (forgive
> >>> my inexperienced 4.0 syntax):
> >>>
> >>> <bean name="passwordValidator"
> >>> class="org.apache.tapestry.valid.StringValidator">
> >>> <set name="minLength" value="6"/>
> >>> <set name="maxLength" value="12"/>
> >>> </bean>
> >>> <bean name="patternValidator"
> >>> class="org.apache.tapestry.valid.PatternValidator">
> >>> <set name="pattern" value="... some regular expression ..."/>
> >>> </bean>
> >>> <bean name="confirmPasswordValidator"
> >>> class="org.apache.tapestry.valid.EqualsValidator">
> >>> <set name="value" value="ognl:user.password"/>
> >>> </bean>
> >>>
> >>> <property name="user"/>
> >>> <property name="confirmationPassword"/>
> >>>
> >>> <component id="password" type="TextField">
> >>> <binding name="value" value="ognl:user.password"/>
> >>> <binding name="label" value="Password"/>
> >>> <binding name="required" value="true"/>
> >>> <binding name="validators" value="{beans.passwordValidator,
> >>> beans.patternValidator}"/>
> >>> </component>
> >>> <component id="confirmPassword" type="TextField">
> >>> <binding name="value" value="ognl:confirmPassword"/>
> >>> <binding name="label" value="Confirmation Password"/>
> >>> <binding name="required" value="true"/>
> >>> <binding name="validators" value="bean:confirmPasswordValidator"/>
> >>> </component>
> >>>
> >>> Thoughts?
> >>>
> >> The problem i see with this method is that beans are instantiated
> >> for the lifecycle of the page, thus the confirmPasswordValidator
> >> value will not be updated during the rewind of the page, and the
> >> value will be the same through multiple request... Maybe to avoid
> >> this problem, the confirmPasswordValidator should not hold the value
> >> of the component but the name or a reference to the component.
> >>
> > Sorry, I should have specified lifecycle="none" for the
> > confirmPasswordValidator. That works, no?
> > The other point to make is that validation (after it is decoupled from
> > translation) acts on your model, not fields. That is why I compare
> > "user.password" instead "components.confirmPassword.value". The
> > difference becomes clearer if the values were bound to numbers or
> > dates.
> >
> > Paul
> >
> >> Numa
> >>
> >>> Paul
> >>>
> >>>> The following scenario is quite simple, but we could name
> >>>> validationRules and thus validationRules could be dependant of the
> >>>> success of other validationRules.
> >>>> I don't really know if this is realistic, but it seems to me
> >>>> possible, the problem is i don't know yet enough about the
> >>>> internals of tapestry and the page specification parser.
> >>>> But to implement this solution i would see that we need to change
> >>>> the following things:
> >>>> - modify the page / component specification parser to add
> >>>> support for reading the validationRule (Page/component DTD)
> >>>> - add a helper bean that records the validation rule and their
> >>>> imbrication and interpret then during page rewinding
> >>>> - All validField component or formComponent should implement
> >>>> comparable and overwrite equals
> >>>>
> >>>> In my absolut dreams we could even imagine that the helper bean
> >>>> translate this rule in javascript. or that in the specification we
> >>>> provide a script snippet that performs the validation.
> >>>>
> >>>> Maybe i am dreaming eyes open ;)
> >>>>
> >>>> Please give me some feedback about this idea if you think it is
> >>>> positive or not so maybe i try to dig more inside tapestry.
> >>>>
> >>>> Kind Regards
> >>>>
> >>>> Numa
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>> --------------------------------------------------------------------
> >>>> -
> >>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
> >>>> For additional commands, e-mail:
> >>>> [EMAIL PROTECTED]
> >>>>
> >>>
> >>>
> >>> ---------------------------------------------------------------------
> >>> To unsubscribe, e-mail: [EMAIL PROTECTED]
> >>> For additional commands, e-mail: [EMAIL PROTECTED]
> >>>
> >>>
> >>
> >>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: [EMAIL PROTECTED]
> >> For additional commands, e-mail: [EMAIL PROTECTED]
> >>
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [EMAIL PROTECTED]
> > For additional commands, e-mail: [EMAIL PROTECTED]
> >
> >
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>
--
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator, Jakarta Tapestry
Creator, Jakarta HiveMind
Professional Tapestry training, mentoring, support
and project work. http://howardlewisship.com
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]