Skip to content

Commit ad48da7

Browse files
committed
Basic support for custom validation messages
By default the validation messages comes from tv4.js, but now you can specify your own via the "validationMessages" attribute either in schema (not recomended) or in the form defintion. If it's a string, that is presented to the user on any error *but* required. If it's an object that is treated as an map between tv4.js error codes and a messages. Special "keys" are 'required' and 'default' that do what you think they do.
1 parent 459a1a5 commit ad48da7

File tree

7 files changed

+105
-15
lines changed

7 files changed

+105
-15
lines changed

src/directives/decorators/bootstrap/default.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,5 @@
99
ng-model="$$value$$"
1010
schema-validate="form.schema">
1111

12-
<span class="help-block" ng-show="form.description && !hasError()">{{form.description}} </span>
13-
<span class="help-block" ng-show="hasError()">{{schemaError}}</span>
12+
<span class="help-block">{{ (hasError() && errorMessage(schemaError())) || form.description}}</span>
1413
</div>

src/directives/decorators/bootstrap/select.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,5 @@
88
ng-required="form.required"
99
ng-options="val as name for (val,name) in form.titleMap">
1010
</select>
11-
<span class="help-block" ng-show="form.description && !hasError()">{{form.description}}</span>
12-
<span class="help-block" ng-show="hasError()">{{schemaError}}</span>
11+
<span class="help-block">{{ (hasError() && errorMessage(schemaError())) || form.description}} </span>
1312
</div>

src/directives/decorators/bootstrap/textarea.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@
55
ng-model="$$value$$"
66
schema-validate="form.schema"></textarea>
77

8-
<span class="help-block" ng-show="form.description && !hasError()">{{form.description}} </span>
9-
<span class="help-block" ng-show="hasError()">{{schemaError}} {{ngModel.$error}}</span>
8+
<span class="help-block">{{ (hasError() && errorMessage(schemaError())) || form.description}} </span>
109
</div>

src/directives/schema-validate.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ angular.module('schemaForm').directive('schemaValidate',function(){
66
require: 'ngModel',
77
link: function(scope,element,attrs,ngModel) {
88
scope.ngModel = ngModel;
9+
var error = null;
910
var schema = scope.$eval(attrs.schemaValidate);
1011

1112
ngModel.$parsers.unshift(function(viewValue) {
@@ -43,11 +44,12 @@ angular.module('schemaForm').directive('schemaValidate',function(){
4344
if (result.valid) {
4445
// it is valid
4546
ngModel.$setValidity('schema', true);
47+
error = null;
4648
return viewValue;
4749
} else {
4850
// it is invalid, return undefined (no model update)
4951
ngModel.$setValidity('schema', false);
50-
scope.schemaError = result.error.message;
52+
error = result.error;
5153
return undefined;
5254
}
5355
});
@@ -57,6 +59,10 @@ angular.module('schemaForm').directive('schemaValidate',function(){
5759
return scope.ngModel.$invalid && !scope.ngModel.$pristine;
5860
};
5961

62+
scope.schemaError = function() {
63+
return error;
64+
};
65+
6066
}
6167
};
6268
});

src/services/decorators.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,35 @@ angular.module('schemaForm').provider('schemaFormDecorators',['$compileProvider'
8787
}
8888
}
8989
};
90+
91+
/**
92+
* Error message handler
93+
* An error can either be a schema validation message or a angular js validtion
94+
* error (i.e. required)
95+
*/
96+
scope.errorMessage = function(schemaError,$error) {
97+
//User has supplied validation messages
98+
if (scope.form.validationMessage) {
99+
if (schemaError) {
100+
if (angular.isString(scope.form.validationMessage)) {
101+
return scope.form.validationMessage;
102+
}
103+
104+
return scope.form.validationMessage[schemaError.code] || scope.form.validationMessage.default;
105+
} else {
106+
return scope.form.validationMessage.required || scope.form.validationMessage;
107+
}
108+
}
109+
110+
//No user supplied validation message.
111+
if (schemaError) {
112+
return schemaError.message; //use tv4.js validation message
113+
}
114+
115+
//Otherwise we only use required so it must be it.
116+
return "Required";
117+
118+
};
90119
}
91120
};
92121
}]);

src/services/schema-form.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ angular.module('schemaForm').factory('schemaForm',[function(){
5757
if (schema.readOnly || schema.readonly) f.readonly = schema.readOnly || schema.readonly;
5858
if (schema.minimum) f.minimum = schema.minimum + (schema.exclusiveMinimum?1:0);
5959
if (schema.maximum) f.maximum = schema.maximum - (schema.exclusiveMaximum?1:0);
60+
61+
//Non standard attributes
62+
if (schema.validationMessage) f.validationMessage = schema.validationMessage;
63+
if (schema.enumNames) f.titleMap = schema.enumNames;
6064
f.schema = schema;
6165
return f;
6266
};
@@ -110,10 +114,12 @@ angular.module('schemaForm').factory('schemaForm',[function(){
110114
var f = stdFormObj(schema,options);
111115
f.key = options.path;
112116
f.type = 'select';
113-
f.titleMap = {};
114-
schema.enum.forEach(function(name){
115-
f.titleMap[name] = name;
116-
});
117+
if (!f.titleMap) {
118+
f.titleMap = {};
119+
schema.enum.forEach(function(name){
120+
f.titleMap[name] = name;
121+
});
122+
}
117123
options.lookup[options.path] = f;
118124
return f;
119125
}
@@ -124,10 +130,12 @@ angular.module('schemaForm').factory('schemaForm',[function(){
124130
var f = stdFormObj(schema,options);
125131
f.key = options.path;
126132
f.type = 'checkboxes';
127-
f.titleMap = {};
128-
schema.items.enum.forEach(function(name){
129-
f.titleMap[name] = name;
130-
});
133+
if (!f.titleMap) {
134+
f.titleMap = {};
135+
schema.items.enum.forEach(function(name){
136+
f.titleMap[name] = name;
137+
});
138+
}
131139
options.lookup[options.path] = f;
132140
return f;
133141
}

test/schema-form-test.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,56 @@ describe('Schema form',function(){
328328
});
329329
});
330330

331+
it('should display custom validationMessages when specified',function(done){
332+
333+
inject(function($compile,$rootScope){
334+
var scope = $rootScope.$new();
335+
scope.person = {};
336+
337+
scope.schema = {
338+
"type": "object",
339+
"properties": {
340+
"name": {
341+
"type": "string",
342+
"pattern": "^[a-z]+",
343+
"validationMessage": "You are only allowed lower case letters in name."
344+
},
345+
"nick": {
346+
"type": "string",
347+
"pattern": "^[a-z]+",
348+
},
349+
}
350+
};
351+
352+
scope.form = [
353+
"name",
354+
{
355+
key: 'nick',
356+
validationMessage: 'Foobar'
357+
}
358+
];
359+
360+
var tmpl = angular.element('<form name="theform" sf-schema="schema" sf-form="form" sf-model="person"></form>');
361+
362+
$compile(tmpl)(scope);
363+
$rootScope.$apply();
364+
tmpl.find('input').each(function(){
365+
$(this).scope().ngModel.$setViewValue('AÖ');
366+
});
367+
368+
var errors = tmpl.find('.help-block');
369+
370+
//timeout so we can do a second $apply
371+
setTimeout(function(){
372+
$rootScope.$apply(); //this actually updates the view with error messages
373+
errors.eq(0).text().should.be.equal("You are only allowed lower case letters in name.");
374+
errors.eq(1).text().should.be.equal("Foobar");
375+
done();
376+
},0);
377+
378+
});
379+
});
380+
331381

332382
it('should use ng-required on required fields',function(){
333383

0 commit comments

Comments
 (0)