Skip to content
This repository has been archived by the owner on May 18, 2024. It is now read-only.

Commit

Permalink
implemented all the validators from readme
Browse files Browse the repository at this point in the history
  • Loading branch information
dnagir committed Dec 22, 2011
1 parent 071fcc1 commit 6e5a9b9
Show file tree
Hide file tree
Showing 3 changed files with 201 additions and 7 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -95,10 +95,10 @@ class @Page extends ko.Model
@numericality 'rating', min: 1, max: 5 @numericality 'rating', min: 1, max: 5


# Inclusion/exclusion # Inclusion/exclusion
@inclusion 'subdomain', ["mine", "yours"] @inclusion 'subdomain', values: ["mine", "yours"]
@exclusion 'subdomain', ["www", "www2"] @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 @length 'name', min: 3, max: 10 # Stringish value should be with the range


# Custom message # Custom message
Expand All @@ -112,7 +112,7 @@ class @Page extends ko.Model
if (page.name() || '').indexOf('funky') < 0 then "should be funky" else null 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 ```coffee
Expand All @@ -125,8 +125,8 @@ ko.Validations.validators.funky = (model, field, options) ->
so that you can use it like so: so that you can use it like so:


```coffee ```coffee
validates: -> @validates: ->
funky 'name', {word: 'yakk'} funky 'name', word: 'yakk'
``` ```


Here's how you would check whether the model is valid or not (assuming presence validation on `name` field): Here's how you would check whether the model is valid or not (assuming presence validation on `name` field):
Expand Down
66 changes: 65 additions & 1 deletion lib/assets/javascripts/knockout/validators.js.coffee
Original file line number Original file line Diff line number Diff line change
@@ -1,18 +1,82 @@
#= require knockout/validations #= require knockout/validations


ko.Validations.validators = 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) -> presence: (model, field, options) ->
val = model[field]() val = model[field]()
isBlank = !val or val.toString().isBlank() isBlank = !val or val.toString().isBlank()

if isBlank then options.message || "can't be blank" else null if isBlank then options.message || "can't be blank" else null



email: (model, field, options) -> email: (model, field, options) ->
val = model[field]() val = model[field]()
isValid = !val or val.toString().match /.+@.+\..+/ isValid = !val or val.toString().match /.+@.+\..+/
unless isValid then options.message or "should be a valid email" else null 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) -> custom: (model, field, options) ->
# Treat options as a mandatory callback # Treat options as a mandatory callback
options.call(model, model) options.call(model, model)
Expand Down
130 changes: 130 additions & 0 deletions spec/javascripts/knockout/validators_spec.js.coffee
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -68,3 +68,133 @@ describe "ko.Validations.validators", ->
isError (model) -> isError (model) ->
expect(model.name()).toBe 'val' 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"

0 comments on commit 6e5a9b9

Please sign in to comment.