Sorry to respond so late. On 5 mai 05, at 19:52, Paul Ferraro wrote:
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?!Numa Schmeder wrote:
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).Hello,
Thanks to all for the feedback. See my comment below:
On 4 mai 05, at 21:00, Paul Ferraro wrote:
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.Numa Schmeder wrote:
Currently, the IValidator interface serves triple duty and is responsible for: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.
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.
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?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.
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>
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?
Sorry, I should have specified lifecycle="none" for the confirmPasswordValidator. That works, no?
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.
- 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: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):
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.
<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 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]
