Skip to content
This repository has been archived by the owner on Dec 25, 2017. It is now read-only.

Commit

Permalink
feat(errors): add validator-errors and validator-error component
Browse files Browse the repository at this point in the history
  • Loading branch information
kazupon committed Feb 15, 2016
1 parent 8d6fce8 commit a51829a
Show file tree
Hide file tree
Showing 5 changed files with 369 additions and 0 deletions.
37 changes: 37 additions & 0 deletions src/components/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export default function (Vue) {

/**
* ValidatorError component
*/

let error = {
name: 'validator-error',

props: {
field: {
type: String,
required: true
},
validator: {
type: String
},
message: {
type: String,
required: true
},
partial: {
type: String,
default: 'validator-error-default'
}
},

template: '<template><partial :name="partial"></partial></template>',

partials: {}
}

// only use ValidatorError component
error.partials['validator-error-default'] = '<p>{{field}}: {{message}}</p>'

return error
}
80 changes: 80 additions & 0 deletions src/components/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import ValidatorError from './error'


export default function (Vue) {

// import ValidatorError component
const error = ValidatorError(Vue)


/**
* ValidatorErrors component
*/

let errors = {
name: 'validator-errors',

props: {
validation: {
type: Object,
required: true
},
group: {
type: String,
default: null
},
field: {
type: String,
default: null
},
component: {
type: String,
default: 'validator-error'
}
},

computed: {
errors () {
let ret = []
if (this.group !== null) {
for (let field in this.validation[this.group].errors) {
for (let validator in this.validation[this.group].errors[field]) {
let message = this.validation[this.group].errors[field][validator]
ret.push({ field: field, validator: validator, message: message })
}
}
} else if (this.field === null) {
for (let field in this.validation.errors) {
for (let validator in this.validation.errors[field]) {
let message = this.validation.errors[field][validator]
ret.push({ field: field, validator: validator, message: message })
}
}
} else {
for (let validator in this.validation.errors[this.field]) {
let message = this.validation.errors[this.field][validator]
ret.push({ field: this.field, validator: validator, message: message })
}
}
return ret
}
},

template: '<template v-for="error in errors">' +
'<component :is="component" :partial="partial" :field="error.field" :validator="error.validator" :message="error.message"></component>' +
'</template>',

components: {}
}

// define 'partial' prop
errors.props['partial'] = error.props['partial']

// only use ValidatorErrors component
errors.components[error.name] = error

// install ValidatorErrors component
Vue.component(errors.name, errors)

return errors
}
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Asset from './asset'
import Override from './override'
import Validate from './directives/validate'
import Validator from './directives/validator'
import Errors from './components/errors'


/**
Expand All @@ -20,6 +21,7 @@ function plugin (Vue, options = {}) {

util.Vue = Vue
Asset(Vue)
Errors(Vue)

Override(Vue)
Validator(Vue)
Expand Down
249 changes: 249 additions & 0 deletions test/specs/components/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
import assert from 'power-assert'
import Vue from 'vue'
import { each } from '../../../src/util'


describe('validator-errors', () => {
let el, vm

beforeEach(() => {
el = document.createElement('div')
})


describe('basic', () => {
beforeEach((done) => {
el.innerHTML =
'<validator name="validation">' +
'<input type="text" v-validate:field1="field1">' +
'<input type="text" v-validate:field2="field2">' +
'<validator-errors :validation="$validation"></validator-errors>' +
'</validator>'
vm = new Vue({
el: el,
data: {
field1: { pattern: { rule: '/foo/', message: 'field1 pattern error' } },
field2: {
required: { rule: true, message: 'field2 required' },
minlength: { rule: 2, message: 'field2 short too' }
}
}
})
vm.$nextTick(done)
})

it('should be rendered error messages', () => {
let matchCount = 0

let errorElements = el.getElementsByTagName('p')
for (var i = 0, l = errorElements.length; i < l; i++) {
var element = errorElements[i]
each([
'field1: field1 pattern error',
'field2: field2 required',
'field2: field2 short too'
], (msg) => {
if (msg === element.textContent) {
matchCount++
}
})
}

assert(matchCount === errorElements.length)
})
})


describe('partial', () => {
beforeEach((done) => {
el.innerHTML =
'<validator name="validation">' +
'<input type="text" v-validate:field1="field1">' +
'<input type="text" v-validate:field2="field2">' +
'<validator-errors :partial="\'custom-error\'":validation="$validation"></validator-errors>' +
'</validator>'
vm = new Vue({
partials: {
'custom-error': '<span>{{field}}:{{validator}}:{{message}}</span>'
},
data: {
field1: { pattern: { rule: '/foo/', message: 'field1 pattern error' } },
field2: {
required: { rule: true, message: 'field2 required' },
minlength: { rule: 2, message: 'field2 short too' }
}
}
}).$mount()
vm.$nextTick(() => {
vm.$appendTo(el)
done()
})
})

it('should be rendered error messages', () => {
let matchCount = 0

let errorElements = el.getElementsByTagName('span')
for (var i = 0, l = errorElements.length; i < l; i++) {
var element = errorElements[i]
each([
'field1:pattern:field1 pattern error',
'field2:required:field2 required',
'field2:minlength:field2 short too'
], (msg) => {
if (msg === element.textContent) {
matchCount++
}
})
}

assert(matchCount === errorElements.length)
})
})


describe('component', () => {
beforeEach((done) => {
el.innerHTML =
'<validator name="validation">' +
'<input type="text" v-validate:field1="field1">' +
'<input type="text" v-validate:field2="field2">' +
'<validator-errors :component="\'custom-error\'" :validation="$validation"></validator-errors>' +
'</validator>'
Vue.component('custom-error', {
props: ['field', 'validator', 'message'],
template: '<div>{{field}}:{{validator}}:{{message}}</div>'
})
vm = new Vue({
el: el,
data: {
field1: { pattern: { rule: '/foo/', message: 'field1 pattern error' } },
field2: {
required: { rule: true, message: 'field2 required' },
minlength: { rule: 2, message: 'field2 short too' }
}
}
})
vm.$nextTick(done)
})

it('should be rendered error messages', () => {
let matchCount = 0

let errorElements = el.getElementsByTagName('div')
for (var i = 0, l = errorElements.length; i < l; i++) {
var element = errorElements[i]
each([
'field1:pattern:field1 pattern error',
'field2:required:field2 required',
'field2:minlength:field2 short too'
], (msg) => {
if (msg === element.textContent) {
matchCount++
}
})
}

assert(matchCount === errorElements.length)
})
})


describe('group', () => {
beforeEach((done) => {
el.innerHTML =
'<validator :groups="[\'group1\', \'group2\']" name="validation">' +
'<input type="text" group="group1" v-validate:field1="field1">' +
'<input type="text" group="group1" v-validate:field2="field2">' +
'<input type="text" group="group2" v-validate:field3="field3">' +
'<input type="text" group="group2" v-validate:field4="field4">' +
'<input type="text" group="group1" value="0" v-validate:field5="{ min: { rule :1, message: message1 } }">' +
'<input type="text" group="group2" value="foo" v-validate:field6="{ minlength: { rule: 4, message: onMessage2 } }">' +
'<validator-errors :group="\'group1\'" :validation="$validation"></validator-errors>' +
'</validator>'
vm = new Vue({
el: el,
data: {
field1: { pattern: { rule: '/foo/', message: 'field1 pattern error' } },
field2: { required: { rule: true, message: 'field2 required' } },
field3: { max: { rule: 3, message: 'field3 big too' } },
field4: { maxlength: { rule: 3, message: 'field4 long too' } }
},
computed: {
message1 () {
return 'field5 small too'
}
},
methods: {
onMessage2 (field) {
return 'field6 short too ' + field
}
}
})
vm.$nextTick(done)
})

it('should be rendered error messages', () => {
let matchCount = 0

let errorElements = el.getElementsByTagName('p')
for (var i = 0, l = errorElements.length; i < l; i++) {
var element = errorElements[i]
each([
'field1: field1 pattern error',
'field2: field2 required',
'field5: field5 small too'
], (msg) => {
console.log(msg, element.textContent)
if (msg === element.textContent) {
matchCount++
}
})
}

assert(matchCount === errorElements.length)
})
})


describe('field', () => {
beforeEach((done) => {
el.innerHTML =
'<validator name="validation">' +
'<input type="text" v-validate:field1="field1">' +
'<input type="text" v-validate:field2="field2">' +
'<validator-errors :field="\'field2\'" :validation="$validation"></validator-errors>' +
'</validator>'
vm = new Vue({
el: el,
data: {
field1: { pattern: { rule: '/foo/', message: 'field1 pattern error' } },
field2: {
required: { rule: true, message: 'field2 required' },
minlength: { rule: 2, message: 'field2 short too' }
}
}
})
vm.$nextTick(done)
})

it('should be rendered error messages', () => {
let matchCount = 0

let errorElements = el.getElementsByTagName('p')
for (var i = 0, l = errorElements.length; i < l; i++) {
var element = errorElements[i]
each([
'field2: field2 required',
'field2: field2 short too'
], (msg) => {
if (msg === element.textContent) {
matchCount++
}
})
}

assert(matchCount === errorElements.length)
})
})
})
1 change: 1 addition & 0 deletions test/specs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require('./invalid')
require('./event')
require('./group')
require('./multiple')
require('./components/errors')
require('./messages')
require('./lazy')
require('./checkbox')
Expand Down

0 comments on commit a51829a

Please sign in to comment.