Skip to content

Commit 6fb7ddb

Browse files
authored
Merge pull request #5 from formly-js/validation-messages
Implemented validation messages.
2 parents 964a43e + 7f9c8c1 commit 6fb7ddb

File tree

6 files changed

+240
-60
lines changed

6 files changed

+240
-60
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-formly",
3-
"version": "2.1.0",
3+
"version": "2.2.0",
44
"description": "A simple and extendable form builder for Vue.js",
55
"main": "dist/vue-formly.js",
66
"scripts": {

src/components/FormlyField.vue

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<script>
66
const Vue = require('vue');
7-
import Util, {getTypes, setError} from '../util';
7+
import Util, {getTypes, setError, parseValidationString} from '../util';
88
export default {
99
props: ['form', 'model', 'field', 'to'],
1010
computed: {
@@ -38,9 +38,22 @@
3838
if ( !this.field.required && !this.model[ this.field.key ] ) return;
3939
4040
let validator = this.field.validators[validKey];
41+
let validatorMessage = false;
4142
43+
if ( typeof validator === 'object' ){
44+
if ( !( 'message' in validator ) ){
45+
console.error( "Looks like you've set a validator object without setting a message. If you don't need to explicity set the message just define the validator as either an expression or a function. Refer to the docs for more info");
46+
} else {
47+
validatorMessage = validator.message;
48+
validator = validator.expression;
49+
}
50+
}
51+
52+
let label = ( 'templateOptions' in this.field ) && ( 'label' in this.field.templateOptions ) ? this.field.templateOptions.label : '';
53+
validatorMessage = parseValidationString( validKey, validatorMessage, label, model[ this.field.key ] );
54+
4255
let valid = typeof validator == 'function' ? !validator(field, model) : !eval(validator);
43-
setError(this.form, this.field.key, validKey, valid);
56+
setError(this.form, this.field.key, validKey, valid, validatorMessage);
4457
4558
});
4659
}

src/index.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
import Components from './components/index';
22
import Filters from './filters/index';
3-
import Util,{getTypes, addType} from './util';
3+
import Util,{getTypes, addType, addValidationMessage} from './util';
44

55

66
let Formly = {
7-
getTypes,
8-
addType,
9-
install(Vue, options){
10-
11-
//install our components
12-
Components(Vue);
13-
Filters(Vue);
7+
getTypes,
8+
addType,
9+
addValidationMessage,
10+
install(Vue, options){
11+
12+
//install our components
13+
Components(Vue);
14+
Filters(Vue);
1415

15-
Vue.$formly = {getTypes, addType};
16-
}
16+
Vue.$formly = {getTypes, addType, addValidationMessage};
17+
}
1718
};
1819

1920
//auto install
2021
if (typeof window !== 'undefined' && window.Vue) {
21-
window.Vue.use(Formly);
22-
//expose formly functions if auto installed
23-
window.Vue.$formly = {getTypes, addType};
22+
window.Vue.use(Formly);
23+
//expose formly functions if auto installed
24+
window.Vue.$formly = {getTypes, addType, addValidationMessage};
2425
}
2526
export default Formly;

src/util.js

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const exports = {
2-
formlyFields: {}
2+
formlyFields: {},
3+
validationMessages: {}
34
};
45
export default exports;
56

@@ -11,11 +12,11 @@ export default exports;
1112
* @param {Object} options
1213
*/
1314
export function addType(id, options){
14-
exports.formlyFields['formly_'+id] = options;
15+
exports.formlyFields['formly_'+id] = options;
1516
}
1617

1718
export function getTypes(){
18-
return exports.formlyFields;
19+
return exports.formlyFields;
1920
}
2021

2122
/**
@@ -25,7 +26,37 @@ export function getTypes(){
2526
* @param {String} err
2627
* @param {Bool} isError
2728
*/
28-
export function setError(form, key, err, isError){
29-
if ( !form.$errors[key] ) form.$errors[key] = {};
30-
form.$errors[key][err] = isError;
29+
export function setError(form, key, err, isError, message = false){
30+
if ( !form.$errors[key] ) form.$errors[key] = {};
31+
form.$errors[key][err] = isError ? message || isError : false;
32+
}
33+
34+
/**
35+
* Adds a validation string to Vue Formly to be used later on by validations
36+
* @param {string} key
37+
* @param {string} message
38+
*/
39+
export function addValidationMessage(key, message){
40+
exports.validationMessages[ key ] = message;
41+
}
42+
43+
/**
44+
* Given a message key or message it parses in the label and the value
45+
* @param {string/bool} key
46+
* @param {string} message
47+
* @param {string} label
48+
* @param {string} value
49+
*/
50+
export function parseValidationString(key, message, label, value){
51+
52+
// if a key has been passed and there's no validation message and no message has been passed then return
53+
if ( key && !(key in exports.validationMessages ) && !message ) return false;
54+
55+
// first check if a validation message with this key exists
56+
if ( key in exports.validationMessages ){
57+
message = exports.validationMessages[key];
58+
}
59+
60+
let output = message.replace(/\%l/g, label).replace(/\%v/g, value);
61+
return output;
3162
}

test/unit/specs/FormlyField.spec.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import chai from 'chai';
22
const expect = chai.expect;
33
import Vue from 'vue';
44
import FormlyField from 'src/components/FormlyField.vue';
5+
import Utils from 'src/util';
56

67
let el, vm;
78

@@ -284,6 +285,114 @@ describe('FormlyField', () => {
284285
done();
285286
},0);
286287
});
288+
289+
describe("Validation Messages", (done) => {
290+
291+
//what do we want to do
292+
293+
//--- define messages ---
294+
//vf.addValidationString('validatorKey', 'message');
295+
296+
//add specific messages
297+
/*
298+
* validators: {
299+
* test: {
300+
* expression: function(){},
301+
* message: '%l requires 10, you entered %s'
302+
* }
303+
* }
304+
*/
305+
306+
it('Inline messages', () => {
307+
let data = {
308+
form: {
309+
$valid: true,
310+
$errors: {}
311+
},
312+
model: {
313+
search: 'testing'
314+
},
315+
fields: [
316+
{
317+
key: 'search',
318+
type: 'test',
319+
validators: {
320+
validatorMessage:
321+
{
322+
expression: 'model.search == "test"',
323+
message: 'Must equal test'
324+
}
325+
}
326+
}
327+
]
328+
};
329+
330+
createValidField(data);
331+
expect(vm.form.$errors.search.validatorMessage).to.equal('Must equal test');
332+
});
333+
334+
it('Inline messages with values parsed', () => {
335+
let data = {
336+
form: {
337+
$valid: true,
338+
$errors: {}
339+
},
340+
model: {
341+
search: 'testing'
342+
},
343+
fields: [
344+
{
345+
key: 'search',
346+
type: 'test',
347+
templateOptions: {
348+
label: 'test'
349+
},
350+
validators: {
351+
validatorMessage:
352+
{
353+
expression: 'model.search == "test"',
354+
message: '%l and %v'
355+
}
356+
}
357+
}
358+
]
359+
};
360+
361+
createValidField(data);
362+
expect(vm.form.$errors.search.validatorMessage).to.equal('test and testing');
363+
});
364+
365+
it('Global messages with values parsed', () => {
366+
let data = {
367+
form: {
368+
$valid: true,
369+
$errors: {}
370+
},
371+
model: {
372+
search: 'testing'
373+
},
374+
fields: [
375+
{
376+
key: 'search',
377+
type: 'test',
378+
templateOptions: {
379+
label: 'test'
380+
},
381+
validators: {
382+
validatorMessage: 'model.search == "test"',
383+
}
384+
}
385+
]
386+
};
387+
388+
//just mock the other vue functions
389+
Utils.validationMessages.validatorMessage = '%l and %v';
390+
391+
createValidField(data);
392+
expect(vm.form.$errors.search.validatorMessage).to.equal('test and testing');
393+
});
394+
395+
});
287396

288397
});
289398

test/unit/specs/index.spec.js

Lines changed: 64 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,73 @@
11
import {expect} from 'chai';
22

33
import VueFormly from 'src/index';
4-
import Util, {addType, getTypes, setError} from 'src/util';
4+
import Util, {addType, getTypes, setError, addValidationMessage, parseValidationString} from 'src/util';
55

66

77
describe('module', () => {
88

9-
it('module props', () => {
10-
expect(VueFormly).to.exist;
11-
expect(VueFormly.install).to.be.a('function');
12-
expect(VueFormly.addType).to.be.a('function');
13-
expect(VueFormly.getTypes).to.be.a('function');
14-
expect(addType).to.be.a('function');
15-
expect(getTypes).to.be.a('function');
16-
expect(setError).to.be.a('function');
17-
expect(Util.formlyFields).to.be.a('object');
18-
});
19-
20-
it('should add fields to Vue', () => {
21-
22-
//mock vue
23-
window.Vue = {
24-
component(){},
25-
filter(){}
26-
};
27-
VueFormly.install(Vue);
28-
29-
let newField = {
30-
foo: 'bar'
31-
};
32-
addType('test', newField);
33-
expect(getTypes().formly_test).to.deep.equal(newField);
34-
});
35-
36-
it('should handle errors',()=>{
37-
let form = {
38-
$errors: {}
39-
};
40-
setError(form, 'fname', 'required', true);
41-
expect(form.$errors.fname.required).to.be.true;
42-
43-
setError(form, 'fname', 'required', false);
44-
expect(form.$errors.fname.required).to.be.false;
45-
});
9+
it('module props', () => {
10+
expect(VueFormly).to.exist;
11+
expect(VueFormly.install).to.be.a('function');
12+
expect(VueFormly.addType).to.be.a('function');
13+
expect(VueFormly.getTypes).to.be.a('function');
14+
expect(VueFormly.addValidationMessage).to.be.a('function');
15+
expect(addType).to.be.a('function');
16+
expect(getTypes).to.be.a('function');
17+
expect(setError).to.be.a('function');
18+
expect(Util.formlyFields).to.be.a('object');
19+
});
20+
21+
it('addType()', () => {
22+
23+
//mock vue
24+
window.Vue = {
25+
component(){},
26+
filter(){}
27+
};
28+
VueFormly.install(Vue);
29+
30+
let newField = {
31+
foo: 'bar'
32+
};
33+
addType('test', newField);
34+
expect(getTypes().formly_test).to.deep.equal(newField);
35+
});
36+
37+
it('setError()',()=>{
38+
let form = {
39+
$errors: {}
40+
};
41+
setError(form, 'fname', 'required', true);
42+
expect(form.$errors.fname.required).to.be.true;
43+
44+
setError(form, 'fname', 'required', false);
45+
expect(form.$errors.fname.required).to.be.false;
46+
47+
setError(form, 'fname', 'required', true, 'Hey there');
48+
expect(form.$errors.fname.required).to.equal('Hey there');
49+
50+
setError(form, 'fname', 'required', false, 'Hey there');
51+
expect(form.$errors.fname.required).to.be.false;
52+
});
53+
54+
it('addValidationMessage()', () => {
55+
addValidationMessage('test', 'testing');
56+
expect(Util.validationMessages.test).to.equal('testing');
57+
});
58+
59+
it('parseValidationString()', () => {
60+
addValidationMessage('parseTest', '%l just %v testing');
61+
let message = '%l just %v testing';
62+
let expected = 'label just value testing';
63+
let output = parseValidationString('parseTest', false, 'label', 'value');
64+
expect(output).to.equal(expected);
4665

66+
output = parseValidationString(false, message, 'label', 'value');
67+
expect(output).to.equal(expected);
68+
69+
output = parseValidationString('blahblahblah', false, '', '');
70+
expect(output).to.be.false;
71+
});
72+
4773
});

0 commit comments

Comments
 (0)