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 manually validation error message settings
Browse files Browse the repository at this point in the history
Closes #70
  • Loading branch information
kazupon committed Feb 22, 2016
1 parent cc19283 commit 83f5806
Show file tree
Hide file tree
Showing 5 changed files with 289 additions and 6 deletions.
103 changes: 103 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,109 @@ Vue.validator('url', function (val) {
new Vue({ el: '#app' })
```

## Manually error message settings

Sometimes, you need to manually set the validation error message such as server-side validation error. At that time, you can apply some error messages to validation results with using `$setValidationErrors` meta method.

### vm.$setValidationErrors(erros)

- **Arguments:**
- `Array<Object>` errors
- `{String}` feild
- `{String}` message
- `{String}` validator [optional]

- **Usage:**

Set the `errors` to validation result errors. This is useful when you want to set manually some errors of server-side validation.

- **Example:**

```html
<div id="app">
<validator name="validation">
<div class="username">
<label for="username">username:</label>
<input id="username" type="text" v-model="username" v-validate:username="{
required: { rule: true, message: 'required you name !!' }
}">
</div>
<div class="old">
<label for="old">old password:</label>
<input id="old" type="text" v-model="passowrd.old" v-validate:old="{
required: { rule: true, message: 'required you old password !!' }
}"/>
</div>
<div class="new">
<label for="new">new password:</label>
<input id="new" type="text" v-model="password.new" v-validate:new="{
required: { rule: true, message: 'required you new password !!' },
minlength: { rule: 8, message: 'your new password short too !!' }
}"/>
</div>
<div class="confirm">
<label for="confirm">confirm password:</label>
<input id="confirm" type="text" v-validate:confirm="{
required: { rule: true, message: 'required you confirm password !!' },
confirm: { rule: true, message: 'your confirm password incorrect !!' }
}"/>
</div>
<div class="errors">
<validator-errors :validation="$validation"></validator-errors>
</div>
<button type="button" v-if="$validation.valid" @click.prevent="onSubmit">update</button>
</validator>
</div>
```
```javascript
new Vue({
el: '#app',
data: {
id: 1,
username: '',
password: {
old: '',
new: ''
}
},
validators: {
confirm: function (val) {
return this.password.new === val
}
},
methods: {
onSubmit: function () {
var self = this
var resource = this.$resource('/user/:id')
resource.save({ id: this.id }, {
username: this.username,
passowrd: this.new
}, function (data, stat, req) {
// something handle success ...
// ...
}).error(function (data, stat, req) {
// handle server error
self.$setValidationErrors([
{ field: data.field, message: data.message }
])
})
}
}
})
```

- **Argument: field**

To detect as validation feild error, you need to pass in `field` argument.

- **Argument: message**

To output as validation error messsage, you need to pass in `message` argument.

- **Argument: validator**

In order to detect where the validator error occurred, you pass in `validator` argument.


# Event

Expand Down
78 changes: 78 additions & 0 deletions example/errors/manually/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>manually error message example</title>
<script src="../../../node_modules/vue/dist/vue.min.js"></script>
<script src="../../../dist/vue-validator.min.js"></script>
<style>
.errors { color: red; }
</style>
</head>
<body>
<div id="app">
<validator name="validation">
<div class="username">
<label for="username">username:</label>
<input id="username" type="text" v-model="username" v-validate:username="{
required: { rule: true, message: 'required you name !!' }
}">
</div>
<div class="old">
<label for="old">old password:</label>
<input id="old" type="text" v-model="passowrd.old" v-validate:old="{
required: { rule: true, message: 'required you old password !!' }
}"/>
</div>
<div class="new">
<label for="new">new password:</label>
<input id="new" type="text" v-model="password.new" v-validate:new="{
required: { rule: true, message: 'required you new password !!' },
minlength: { rule: 8, message: 'your new password short too !!' }
}"/>
</div>
<div class="confirm">
<label for="confirm">confirm password:</label>
<input id="confirm" type="text" v-validate:confirm="{
required: { rule: true, message: 'required you confirm password !!' },
confirm: { rule: true, message: 'your confirm password incorrect !!' }
}"/>
</div>
<div class="errors">
<validator-errors :validation="$validation"></validator-errors>
</div>
<button type="button" v-if="$validation.valid" @click.prevent="onSubmit">update</button>
</validator>
</div>
<script>
new Vue({
el: '#app',
data: {
id: 1,
username: '',
password: {
old: '',
new: ''
}
},
validators: {
confirm: function (val) {
return this.password.new === val
}
},
methods: {
onSubmit: function () {
var self = this

// simulate server validation errors
setTimeout(function () {
self.$setValidationErrors([
{ field: 'old', message: 'sorry, your account is locked !!' }
])
}, 2000)
}
}
})
</script>
</body>
</html>
39 changes: 37 additions & 2 deletions src/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,17 @@ export default class Validator {
this._dir.vm.$validate = (field) => {
this._validate(field)
}

// define manually the validation errors
this._dir.vm.$setValidationErrors = (errors) => {
this._setValidationErrors(errors)
}
}

disableReactive () {
this._dir.vm.$validate = null
this._dir.vm.$validatorReset = null
this._dir.vm.$setValidationErrors = undefined
this._dir.vm.$validate = undefined
this._dir.vm.$validatorReset = undefined
this._dir.vm._validatorMaps[this.name] = null
this._dir.vm[this.name] = null
}
Expand Down Expand Up @@ -116,6 +122,35 @@ export default class Validator {
this.validate()
}

_setValidationErrors (errors) {
const extend = util.Vue.util.extend

// make tempolaly errors
let temp = {}
each(errors, (error, index) => {
if (!temp[error.field]) {
temp[error.field] = []
}
temp[error.field].push(error)
})

// set errors
each(temp, (values, field) => {
let validation = this._scope[field]
let newValidation = {}
each(values, (error) => {
if (error.validator) {
validation[error.validator] = error.message
}
})
validation.valid = false
validation.invalid = true
validation.errors = values
extend(newValidation, validation)
util.Vue.set(this._scope, field, newValidation)
}, this)
}

// TODO: should be improved performance (use cache)
get validations () {
const extend = util.Vue.util.extend
Expand Down
73 changes: 70 additions & 3 deletions test/specs/messages.js → test/specs/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Vue from 'vue'
import { each, empty, trigger } from '../../src/util'


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

let testMatches = (target, validatorErrors) => {
Expand Down Expand Up @@ -57,7 +57,8 @@ describe('messages', () => {
vm.$nextTick(done)
})

context('invalid', () => {

describe('invalid', () => {
beforeEach((done) => {
let field3 = el.getElementsByTagName('input')[2]
field3.value = '4'
Expand Down Expand Up @@ -123,7 +124,7 @@ describe('messages', () => {
})


context('valid', () => {
describe('valid', () => {
beforeEach((done) => {
let field1 = el.getElementsByTagName('input')[0]
field1.value = 'foo'
Expand Down Expand Up @@ -186,4 +187,70 @@ describe('messages', () => {
})
})
})


describe('$setValidationErrors', () => {
beforeEach((done) => {
let field1 = el.getElementsByTagName('input')[0]
field1.value = 'foo'
trigger(field1, 'input')
trigger(field1, 'blur')
vm.$nextTick(() => {
let field2 = el.getElementsByTagName('input')[1]
field2.value = 'hello'
trigger(field2, 'input')
trigger(field2, 'blur')
vm.$nextTick(() => {
let field3 = el.getElementsByTagName('input')[2]
field3.value = '1'
trigger(field3, 'input')
trigger(field3, 'blur')
vm.$nextTick(() => {
let field4 = el.getElementsByTagName('input')[3]
field4.value = 'hi'
trigger(field4, 'input')
trigger(field4, 'blur')
vm.$nextTick(() => {
let field5 = el.getElementsByTagName('input')[4]
field5.value = '10'
trigger(field5, 'input')
trigger(field5, 'blur')
vm.$nextTick(() => {
let field6 = el.getElementsByTagName('input')[5]
field6.value = 'hello'
trigger(field6, 'input')
trigger(field6, 'blur')
done()
})
})
})
})
})
})

it('should be set errors', (done) => {
vm.$setValidationErrors([
{ field: 'field1', validator: 'pattern', message: 'failed field1 server validation error' },
{ field: 'field5', validator: 'min', message: 'failed field5 server validation error' }
])
vm.$nextTick(() => {
assert(vm.$validation.field1.pattern === 'failed field1 server validation error')
assert(vm.$validation.field1.valid === false)
assert(vm.$validation.field1.invalid === true)
assert(vm.$validation.field1.errors[0].validator === 'pattern')
assert(vm.$validation.field1.errors[0].message === 'failed field1 server validation error')
assert(vm.$validation.field5.min === 'failed field5 server validation error')
assert(vm.$validation.field5.valid === false)
assert(vm.$validation.field5.invalid === true)
assert(vm.$validation.field5.errors[0].validator === 'min')
assert(vm.$validation.field5.errors[0].message === 'failed field5 server validation error')
assert(vm.$validation.valid === false)
assert(vm.$validation.invalid === true)
assert(!empty(vm.$validation.errors))
assert(vm.$validation.group1.errors.length === 2)
assert(empty(vm.$validation.group2.errors))
done()
})
})
})
})
2 changes: 1 addition & 1 deletion test/specs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ require('./event')
require('./group')
require('./multiple')
require('./components/errors')
require('./messages')
require('./errors')
require('./lazy')
require('./checkbox')
require('./radio')
Expand Down

0 comments on commit 83f5806

Please sign in to comment.