Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

implemented all the validators from readme

  • Loading branch information...
commit 6e5a9b98cd97d0f2ece6bcf8322e8ea762b56686 1 parent 071fcc1
Dmytrii Nagirniak dnagir authored
12 README.md
View
@@ -95,10 +95,10 @@ class @Page extends ko.Model
@numericality 'rating', min: 1, max: 5
# Inclusion/exclusion
- @inclusion 'subdomain', ["mine", "yours"]
- @exclusion 'subdomain', ["www", "www2"]
+ @inclusion 'subdomain', values: ["mine", "yours"]
+ @exclusion 'subdomain', values: ["www", "www2"]
- @format 'code', /\d+/ # Regex validation, blanks allowed
+ @format 'code', match: /\d+/ # Regex validation, blanks allowed
@length 'name', min: 3, max: 10 # Stringish value should be with the range
# Custom message
@@ -112,7 +112,7 @@ class @Page extends ko.Model
if (page.name() || '').indexOf('funky') < 0 then "should be funky" else null
```
-It is recommended to avoid custom inline validations and create your own validators instead:
+It is recommended to avoid custom inline validations and create your own validators instead (and maybe submit it as a Pull Request):
```coffee
@@ -125,8 +125,8 @@ ko.Validations.validators.funky = (model, field, options) ->
so that you can use it like so:
```coffee
-validates: ->
- funky 'name', {word: 'yakk'}
+@validates: ->
+ funky 'name', word: 'yakk'
```
Here's how you would check whether the model is valid or not (assuming presence validation on `name` field):
66 lib/assets/javascripts/knockout/validators.js.coffee
View
@@ -1,18 +1,82 @@
#= require knockout/validations
ko.Validations.validators =
+ acceptance: (model, field, options) ->
+ val = model[field]()
+ unless val then options.message || "needs to be accepted" else null
presence: (model, field, options) ->
val = model[field]()
isBlank = !val or val.toString().isBlank()
-
if isBlank then options.message || "can't be blank" else null
+
email: (model, field, options) ->
val = model[field]()
isValid = !val or val.toString().match /.+@.+\..+/
unless isValid then options.message or "should be a valid email" else null
+
+ confirmation: (model, field, options) ->
+ otherField = options.confirms
+ throw "Please specify which field to apply the confirmation to using {confirms: 'otherField'}" unless otherField
+ orig = model[field]()
+ other = model[otherField]()
+ if orig != other and orig then options.message or "should confirm #{otherField}" else null
+
+
+ numericality: (model, field, options) ->
+ val = model[field]()
+ return unless val
+ looksLikeNumeric = val.toString().match /^-?\d+$/ # We should do better than this
+ num = parseInt val, 10
+ min = if options.min? then options.min else num
+ max = if options.max? then options.max else num
+ if looksLikeNumeric and min <= num <= max then null else options.message or "should be numeric"
+
+
+ inclusion: (model, field, options) ->
+ values = options.values
+ throw "Please specify the values {values: [1, 2, 5]}" unless values
+ val = model[field]()
+ return unless val
+ if values.indexOf(val) < 0 then options.message or "should be one of #{values.join(', ')}" else null
+
+
+ exclusion: (model, field, options) ->
+ values = options.values
+ throw "Please specify the values {values: [1, 2, 5]}" unless values
+ val = model[field]()
+ return unless val
+ if values.indexOf(val) >= 0 then options.message or "should not be any of #{values.join(', ')}" else null
+
+ format: (model, field, options) ->
+ matcher = options.match
+ throw "Please specify the match RegEx {match: /\d+/}" unless matcher
+ val = model[field]()
+ return unless val
+ if val.toString().match matcher then null else options.message or "should be formatted properly"
+
+ length: (model, field, options) ->
+ val = model[field]()
+ return unless val
+ val = val.toString().length
+ {min, max} = options
+ min = val unless min?
+ max = val unless max?
+ createMsg = ->
+ minMsg = if options.min?
+ "at least #{min} characters long"
+ else
+ ""
+ maxMsg = if options.max?
+ "no longer than #{max} characters"
+ else
+ ""
+ separator = if minMsg and maxMsg then " but " else ""
+ "should be #{minMsg}#{separator}#{maxMsg}"
+ if min <= val <= max then null else options.message or createMsg()
+
custom: (model, field, options) ->
# Treat options as a mandatory callback
options.call(model, model)
130 spec/javascripts/knockout/validators_spec.js.coffee
View
@@ -68,3 +68,133 @@ describe "ko.Validations.validators", ->
isError (model) ->
expect(model.name()).toBe 'val'
+
+ describe "acceptance", ->
+ isError = (val, opts={}) -> isErrorFor('acceptance', val, opts)
+
+ it "should not allow falsy", ->
+ expect(isError false).toBeTruthy()
+ expect(isError null).toBeTruthy()
+ expect(isError undefined).toBeTruthy()
+ expect(isError '').toBeTruthy()
+
+ it "should allow truthy", ->
+ expect(isError true).toBeFalsy()
+ expect(isError 123).toBeFalsy()
+ expect(isError ' ').toBeFalsy()
+ expect(isError 'x').toBeFalsy()
+
+
+
+ describe "confirmation", ->
+ isError = (val, confirmation) ->
+ model =
+ name: ko.observable(val)
+ other: ko.observable(confirmation)
+ ko.Validations.validators.confirmation(model, 'name', confirms: 'other')
+
+ it "should not allow unconfirmed", ->
+ expect(isError 'a', 'b').toBeTruthy()
+ expect(isError 'a', '').toBeTruthy()
+ expect(isError 'a', null).toBeTruthy()
+
+ it "should allow confirmed", ->
+ expect(isError 'a', 'a').toBeFalsy()
+ expect(isError '', '').toBeFalsy()
+ expect(isError null, null).toBeFalsy()
+ expect(isError undefined, null).toBeFalsy()
+ expect(isError undefined, '').toBeFalsy()
+ expect(isError undefined, 'asd').toBeFalsy()
+ expect(isError '', 'asd').toBeFalsy()
+
+
+
+ describe "numericality", ->
+ isError = (val, opts={}) -> isErrorFor('numericality', val, opts)
+
+ it "should not allow for non-numbers", ->
+ expect(isError "asd").toBeTruthy()
+
+ it "should not allow some numbers", ->
+ expect(isError '123.45').toBeTruthy()
+
+ it "should allow", ->
+ expect(isError "").toBeFalsy()
+ expect(isError undefined).toBeFalsy()
+ expect(isError null).toBeFalsy()
+ expect(isError '123').toBeFalsy()
+
+ it "should respec min option", ->
+ expect(isError 123, min: 200).toBeTruthy()
+ expect(isError 123, min: 100).toBeFalsy()
+ expect(isError 100, min: 100).toBeFalsy()
+
+ expect(isError -1, min: 0).toBeTruthy()
+ expect(isError -1, min: -2).toBeFalsy()
+ expect(isError 0, min: 0).toBeFalsy()
+
+
+
+ describe "inclusion", ->
+ isError = (val, values) -> isErrorFor('inclusion', val, values: values)
+
+ it "should not allow", ->
+ expect(isError 'a', ['b', 'c']).toBeTruthy()
+
+ it "should allow", ->
+ expect(isError 'b', ['b', 'c']).toBeFalsy()
+ expect(isError '', ['b', 'c']).toBeFalsy()
+ expect(isError null, ['b', 'c']).toBeFalsy()
+
+
+
+ describe "exclusion", ->
+ isError = (val, values) -> isErrorFor('exclusion', val, values: values)
+
+ it "should allow", ->
+ expect(isError 'a', ['b', 'c']).toBeFalsy()
+ expect(isError '', ['b', 'c']).toBeFalsy()
+ expect(isError null, ['b', 'c']).toBeFalsy()
+
+ it "should not allow", ->
+ expect(isError 'b', ['b', 'c']).toBeTruthy()
+
+
+
+ describe "format", ->
+ isError = (val, rx) -> isErrorFor('format', val, match: rx)
+
+ it "should not allow", ->
+ expect(isError 'asd', /\d/).toBeTruthy()
+ expect(isError 123, /xxx/).toBeTruthy()
+
+ it "should allow", ->
+ expect(isError '', /asd/).toBeFalsy()
+ expect(isError null, /asd/).toBeFalsy()
+ expect(isError 123, /\d/).toBeFalsy()
+ expect(isError 'asd', /asd/).toBeFalsy()
+
+
+ describe "length", ->
+ isError = (val, options) -> isErrorFor('length', val, options)
+
+ it "with min", ->
+ expect(isError 'x', min: 2).toBeTruthy()
+ expect(isError 'x', min: 1).toBeFalsy()
+ expect(isError 'x', min: 0).toBeFalsy()
+
+ it "with max", ->
+ expect(isError 'xxx', max: 2).toBeTruthy()
+ expect(isError 'xxx', max: 3).toBeFalsy()
+ expect(isError 'xxx', max: 4).toBeFalsy()
+
+ it "should allow", ->
+ expect(isError null, min: 2).toBeFalsy()
+ expect(isError undefined, min: 2).toBeFalsy()
+ expect(isError '', min: 2).toBeFalsy()
+
+ it "should have descriptive message", ->
+ expect(isError 'xxx', min: 11).toBe "should be at least 11 characters long"
+ expect(isError 'xxx', max: 2).toBe "should be no longer than 2 characters"
+ expect(isError 'xxx', min: 1, max: 2).toBe "should be at least 1 characters long but no longer than 2 characters"
+
Please sign in to comment.
Something went wrong with that request. Please try again.