-
Notifications
You must be signed in to change notification settings - Fork 421
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Validation improvements #1111
Comments
What do you mean by
Sent from my iPhone
|
I meant it should be called with a success handler (callback func) and error handler |
@retro might have some input on this. |
can.compute validations discussed in #111 are now part of this. |
What's the status on this feature? Is anyone working on it? |
Related issue #355 I think that validations require more discussion. At the moment you cannot bind validations in a template easily. |
When |
@rjgotten care to make a fiddle showing this? |
Here's my take on validations. I've talked about it with @justinbmeyer today, and we agreed that validations plugin should cover these cases:
Validation of the current stateThis one is pretty easy, and I already have an "external" validation plugin implemented that covers the following cases:
1. Validation of attributesThis is works similarly to the current CanJS validation plugin: var validator = new ValidatorContext(modelInstance, {
username : [ValidatorContext.rules.presenceOf()],
password : [function(value, path){
if(!passwordIsValid){
return "is invalid";
}
}]
})
validator.errors()
// returns
{
username : "can't be empty",
password : "is invalid"
} 2. Validation of nested attributesThis is same as the validation of attributes, but you can use the whole path: var validator = new ValidatorContext(modelInstance, {
"user.username" : [ValidatorContext.rules.presenceOf()]
})
validator.errors()
//returns
{
"user.username" : "can't be empty"
} 3. Validation of arraysThis will validate var validator = new ValidatorContext(modelInstance, {
"users.*.password" : [ValidatorContext.rules.presenceOf()]
})
validator.errors()
//returns
{
"users.1.password" : "can't be empty"
} Format of the attributes that is returned from the validator is similar to the paths returned from the events triggered by You can go to any depth with it. This will validate var validator = new ValidatorContext(modelInstance, {
"users.*.socialNetworks.*.username" : [ValidatorContext.rules.presenceOf()]
})
validator.errors()
// returns
{
"users.1.socialNetworks.2.username" : "can't be empty"
} 4. Validation of arrays that contain simple values (strings, numbers)You can validate strings and numbers in arrays too: var validator = new ValidatorContext(modelInstance, {
"users.*.socialNetworkUsernames.*" : [ValidatorContext.rules.formatOf(REGEX)]
})
validator.errors()
// returns
{
"users.1.socialNetworkUsernames.2" : "is invalid"
} 5. Validation of a whole objectSometimes you wan't to decide which attribute is invalid in the context of the validation: var validator = new ValidatorContext(modelInstance, {
"*" : [function(){
if(this.someThing){
return {
username : 'is invalid'
}
}
}]
})
validator.errors()
// returns
{
"username" : "is invalid"
} In my experience this covers all possible validation needs. Although this library is "external", we could implement the var User = can.Map.extend({
validate : {
username : [can.validate.presenceOf()]
}
}) This could set a special
user.save().then(success, function(req){
user.attr('@errors', JSON.parse(req.responseText));
}) Validation of a future stateAKA: will setting this attribute put my map into the error state? I'm not sure how to approach this, but I believe that it would be best to simply clone the current object, set the value on it and return errors. Something like this could work: var errors = user.errorsFor({attribute : 'value'});
if(errors){
// do something
} Any feedback on this API is welcome. |
@retro What about observing when an error happens? That was the 3rd case. |
@retro I care a lot about getting the "simple" case right too. How could one add a simple email validation in the view layer? Consider something like angular: https://docs.angularjs.org/api/ng/input/input%5Bemail%5D
|
I still think validation is a model concern, not a view concern. That's something just about every framework out there does "wrong" as far as I'm concerned. |
I'm seconding @gsmeets here: You're validating attribute values set on a Also:
Nice that you picked up exactly this example, because it allows me to request an additional validation feature. An oversimplified e-mail validator spitting out a hard error and not allowing a user to set a perfectly valid e-mail address is pretty much the poster-child of bad form-entry UX. (You do know that, I hope.) So; how about adding 'error levels' to validation while we're at it? Explicitly marking hard errors and soft warnings would make it a bit easier to wire up such operations as deciding whether a model is 'error-free' and fit to be processed further, e.g., when a user is working in a form that can be 'posted'. |
I agree, validation should be only in the models, I don't really like the way Angular forces you declare the validation in the form, that is just their workaround because they don't have models. Some people argue that you might want different validations in different contexts, but I don't ever see that need in real apps. |
Validation is not only a model concern. It is a view model concern. It is possible to want validations for the view model independent of the model. This is something we are currently dealing with. A good system allows both. This is akin to what we are suggesting for can.connect by separating CRUD behavior from the data model while still allowing them to be together in a nice package. Sent from my iPhone
|
We are seeing this in real apps. This is why we want to support both. Making a validator its own, data model independent, entity is the first step. Making that mixin-able in a model or a view is the second step. Sent from my iPhone
|
Reusability is greater with validation detachable from the model. Why are pure view validations are not discoverable? Things in the view tend to be the most discoverable. The input, as you somewhat accidentally allude to later (talking about email validation), does factor into the validation. Is something valid while someone is typing, after the input loses focus, or after all fields have been submitted? There's a tremendous amount of ways people do validations. The model-based validations simply have not scaled for us. We are seeking ways of having simple model-based validations and view-based validations based on a validation primitive. And yes, I'm aware of the great many problems facing making workable validation libraries. Most of the time you present the error as a warning, other times you prevent keyboard input (ex: numeric-only). Error levels are unnecessary if you can easily express what the behavior of being in a error state, or transitioning to or from an error state should be. Sent from my iPhone
|
Im with @justinbmeyer validation in the view (if is in declarative manner) will be great flexibility IMO validation on client side should be different from the server (like Rails), maybe parsleyjs can be considerend as example too http://parsleyjs.org/ |
When we talk about validations it's important to separate them in 3 groups:
In my opinion it does make sense to expose protocol validations through the view interface:
Or through some similar API. The trick is to have a system that can combine all three of these in to one errors object. That way view based validations could just be weaved in with the rest of the validations. |
I am wary of putting something like a regex into a template.. templates are (hypothetically) a simple representation of underlying functionality, and there is nothing simple about a regex. Additionally, it is going to defeat syntax validation engines attempts to help people with regex syntax. Specifically, having a validation called out ala |
Agree with @shcarrico . The worst scenario is when someone mis-copies a template regex like this, and introduces subtle, incorrect behavior. There are also the form field types in HTML5. Could we use those http://diveintohtml5.info/forms.html#type-email? The new field types would affect the protocol validations mentioned above, and are well-defined, so they could be baked in. Using these types could have several benefits:
Other types of validation could rely on the other standard input field attributes and would be written to "just work" when the validation engine is enabled. |
Having a regexp was just an example of passing some parameter to some validation function. Don't get hung up on it. Sent from my iPhone
|
Just to be clear on what is being proposed here, several people are keen to have a way to declare validation directly on the templates, but how would that interact with validation on the models? Would you have to duplicate the validation rules? I like having validation in my models as I can use that validation in several places. What is missing for me is a clean way to bind that validation to the views. Re state of validations |
'On blur' is the default behavior; a cross-binding based on, afaik, the The 'on submit' flavor is trickier. You could do it as an option on the cross-binding, sure: it could be based on the Still, a better way to implement it is to enable users to toggle on/off the behavior where validation is run whenever a model attribute is updated. When the application user tries to perform a 'submit' / 'confirm' / 'save' / etc. action, a manual Having such a toggle interactive would also support a scenario where validation feedback is live, but doesn't show until the first time a user tries to perform a submit-like action. One would simply flip the toggle back on when the application user performs the action and live validation feedback jumps back into action (based on either 'on blur' or 'as you type', depending on how cross-bindings are configured). |
I've worked around this using components now in a non-livebound fashion. i.e. I trigger validation manually on change, and I force a validation of pre-set (and possibly invalid) data on submit again using a broadcast to all said components. From then on out the components (and the submit button that triggered it) remain in an invalid state until all errors are resolved. I'm wondering if folding all of that into full observable behaviour isn't going to increase the complexity all over. I'm quite happy with the terseness of my views at the moment. |
I think we can move this discussion into https://github.com/canjs/can-validate |
VOTE HERE
It seems like can/map/validate is sort of like can/map/define::setter but has several differences, and it might make sense to merge them.
Setter supports async, validations doesn't.
Validations supports an "errors" object and "errors" events, both of which are very useful.
I propose merging the validations plugin into define. Or at least making them work together rather than separately.
A couple thoughts:
validate
would be similar toset
, I thinkvalidate
should be separate, because I can think of cases where you'd want the hook provided byset
and validation logic separate.The text was updated successfully, but these errors were encountered: