-
Notifications
You must be signed in to change notification settings - Fork 647
More complicated validation scenarios seems to be not supported #185
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
Comments
Hi @corvis - that's a really great question. It's generally against the goals of this project to change the json-schema spec (which is actually an ietf standard). However, the ability you want is part of the v5 You would do something like: {
"type": "object",
"properties": {
"password": {"type": "string"},
"confirm": {
"constant": {"$data": "1/password"}
}
},
"required": ["password", "confirm"]
} I'm just about 100% sure that TV4 doesn't support this yet (although others like jjv do), so json-schema-form can't support this right now. However, I just wanted to mention this as the "correct" way to do this. I believe there are some other workarounds provided by the form declaration that could allow you to add this functionality, but I'll defer to those more familiar with them. Either way, if you're using a server-side validator that supports |
Hi @mike-marcacci, thanks for really quick reply. {
type: 'object',
properties: {
"confirmPassword": { type: "string", constant: {"$data": "1/password"}}
}
} no password field will be there as such reference Checkout this code snippet from Schema-Form sources (factory sfValidator) which do actual validation. It creates wrap inserts the only property and passes it to tv4: var wrap = {type: 'object', 'properties': {}};
var propName = form.key[form.key.length - 1];
wrap.properties[propName] = schema;
if (form.required) {
wrap.required = [propName];
}
var valueWrap = {};
if (angular.isDefined(value)) {
valueWrap[propName] = value;
}
return tv4.validateResult(valueWrap, wrap); |
Hi @corvis, as @mike-marcacci said generally we don't add stuff to the schema :-). Its not as pretty as a proper schema solution but I'd say this is easiest to solve password fields is an add-on/custom type that type renders two inputs and handles the validation the "standard angular way" by injecting the |
Also I've been pondering adding some kind of support for Angular 1.3s async validators, probably by adding a form attribute to tackle the "check if this username is already taken" scenario. |
I think this is really needed. As far as I can tell, right now, async validators are completely ignored. They run if you set them up, but they don't affect form validity once they return. And I don't see any way to alter the validity of the field or the form within the async validator success or failure callback. Even explicit calls to the ngModelController $setValidity don't seem to have any effect. |
@davidlgj I added that option to from definition, not to the schema. Basically in the save way as validation messages are set. Also here is one more pretty common usecase which will be nice to keep in mind: We have 2 date\time fields: "Publication date" and "Valid due date". And that should be constraint which validates that "Publication date" value is less than "Valid due date" |
In the meantime, if anyone has any ideas about how to wedge async validation into the schema form (particularly from within custom directive controllers), I'd love to hear them. I just keep running into walls trying to make it work. :-/ |
@davidlgj you do not add stuff to schema but you modify it. If you will have logic that will not split or modify schema and use it as it was passed , that would solve this problem and many others. Currently I have same problem but with different scenario. {
"type":"object",
"properties":{
"streetLine1":{
"title":"Street",
"type":"string",
"maxLength": 44,
"minLength": 3
},
"state":{
"title":"State",
"type":"string",
"enum": ["NY", "CT"]
},
"postalCode":{
"title":"ZIP",
"type":"string",
"pattern":"^[0-9]{5}(-[0-9]{4})?$",
"validationMessage":"Please Provide Valid ZIP Code"
},
"isoCountry":{
"title":"Country",
"type":"string",
"enum": ["US", "CA"]
},
"contact": {
"type": "object",
"description": "Contact object",
"anyOf": [
{
"properties": {
"firstName":{
"title":"First Name",
"maxLength":44,
"minLength":1,
"type":"string"
},
"lastName":{
"title":"Last Name",
"maxLength":44,
"minLength":2,
"type":"string"
},
"companyName":{
"title":"Company",
"maxLength":44,
"minLength":3,
"type":"string"
}
},
"required": [
"companyName"
]
}, {
"properties": {
"firstName":{
"title":"First Name",
"maxLength":44,
"minLength":1,
"type":"string"
},
"lastName":{
"title":"Last Name",
"maxLength":44,
"minLength":2,
"type":"string"
},
"companyName":{
"title":"Company",
"maxLength":44,
"minLength":3,
"type":"string"
}
},
"required": [
"firstName",
"lastName"
]
}
],
"properties": {
"middleInitial": {
"title": "Middle Initial",
"maxLength": 1,
"minLength": 1,
"type": "string"
}
}
}
},
"required": ["contact", "isoCountry", "state", "postalCode", "streetLine1"]
} And here object that passes tv4 validation for such schema: var data = {
isoCountry: "US",
state: "CT",
streetLine1: "Street 1",
postalCode:"12345",
contact: {
firstName: "ololo",
lastName: "zzz",
"middleInitial": "s"
}
}; I've tried to use schema-form in different ways but it seems it won't work with such schemas because schema-form modifies it splitting and disabling complex validation. So, as I see it now, schema-form has many of JSON Schema features disabled out of the box. |
@corvis, look for custom decorators, and for postProcess function of schema-form to pass additional data to your form field. |
I fiddled with $asyncValidators and I think I got it working in a custom type, this is my test code: angular.module('test',['schemaForm','ui.ace']).config(function(schemaFormDecoratorsProvider) {
schemaFormDecoratorsProvider.addMapping(
'bootstrapDecorator',
'asynctest',
'async.html'
);
}).run(function($templateCache){
// Get and modify default templates
var tmpl = $templateCache.get('directives/decorators/bootstrap/default.html');
$templateCache.put(
'async.html',
tmpl.replace('type="{{form.type}}"', 'type="text" async-test')
);
}).directive('asyncTest', function($q) {
return {
restrict: 'A',
scope: false,
require: 'ngModel',
link: function(scope, attr, element, ngModel) {
ngModel.$asyncValidators['test'] = function(modelValue, viewValue) {
var value = modelValue || viewValue;
var deferred = $q.defer();
setTimeout(function() {
if (value === 'foo') {
deferred.resolve();
} else {
deferred.reject();
}
scope.$apply();
}, 200)
return deferred.promise;
}
}
}
}) Hope that helps! Ping me if you got any questions |
I found another interesting way to do this without having to modify the actual templates. Using Angular decorators we can do this: app.config(function ($provide) {
$provide.decorator('schemaValidateDirective', function ($delegate) {
var directive = $delegate[0];
var link = directive.link;
directive.compile = function () {
return function (scope, element, attrs, ngModel) {
link.apply(this, arguments);
// ngModel.$asyncValidators is accessible here as well as the sync version.
};
};
return $delegate;
});
}); |
@avishnyak awesome solution! @corvis are you satisfied with the decorator solution? If so please close the issue. |
For me, it turns out that getting my custom directives to use the async validators was only half the battle. It turns out that right now, there's really no way to know when all the async validators (across the form as a whole) are finished. I have an open ticket with the Angular team on this (angular/angular.js#10768). |
@avishnyak can you explain more about your code, how will it affect the validation of the angular-schema-form? will it affect all decorators used by the angular-schema-form, even if it do not contain ng-model directive in the decorator template? can it validate the whole schema to the whole model, or validate the sub-property which is 'object' type schema? if so, how can it reflect the error message to the certain input fields or section? |
@ulion sure! The method I showed above is additive to the decorators that come with angular-schema-form. That portion is handled by this line If you do not use ng-model in your custom templates, it will just come in as undefined to this function (though I haven't tested this scenario). Can it validate the whole schema to the whole model, or validate the sub-property which is 'object' type schema? Unfortunately no. The way this was designed internally, only leaf nodes (ones that are not array or object) actually have validators on them. However, I was able to get around this in a slightly different way. WARNING: This is copy-pasted from my project and modified to remove project-specific items. I haven't compiled this so there may be typo bugs
|
Thank you for your code. but I just still figure out where is the in jsonform they did the whole validation, then in the error message, there why just can not angular-schema-form do this? 2015-02-28 1:57 GMT+08:00 Anton Vishnyak [email protected]:
Ulion |
Sorry, the code I pasted was for you to add your own validation code. That code would go towards the bottom where the comments are. That would allow you to achieve a similar thing to jsonform. You have access to the whole schema and form so you can do whatever you want really. It doesn't do it because it is architected differently. I am on your side in that it makes it difficult to have advanced validation scenarios and hopefully a future version will have a better mechanism. |
I've built a simple demo of a user registration form which includes:
|
Thank you @plong0 I just wonder, for each single validation, we have to write directive? if some easy validation way has to be extended and supported, so the so, can this be done in some easy way? 2015-03-12 0:20 GMT+08:00 plong0 [email protected]:
Ulion |
The Problem
I have create user form which along with other fields contains password and passwordRepeat fields.
Validation should be triggered on blur and the goal is to get "Passwords should match" message near the passwordRepeat field.
Investigation
The first idea was to add custom keyword in JsonSchema which will compare values. Something like this:
equalTo should be registered in tv4 on initialization stage.
However later I realized that angular-schema-form splits original schema by field so each field knows only about own piece of schema which makes impossible to reffer other fields.
Solution
To be honest I didn't find really good solution here. I just forked angular-schema-form repository and added optional callback function in form definition which will be invoked after default validation in case when tv4 decided that value is valid.
Here is usage example from my project:
It should return error code if there is an error and undefined otherwise.
So...
Does anyone have any better ideas? Maybe someone solved similar issue before... Maybe I missed something...
Anyway if you think that this approach is useful and correct I can prepare pull request.
Chears,
Dmitry
The text was updated successfully, but these errors were encountered: