Adds an extender to a knockout object that allows you to validate its values and obtain the errors.
- receives validation description as a parameter, eg:
name = ko.observable().extend
validation: {notEmpty:{message: "Hello world!!"}}
name.validate (isValid)->
name.getAllErrors() # ["Hello World !!!"]
npm install knockout-validations-extender --save
``get knockout-validations-extender.min.js from github dist fodler`
You can access global variable knockoutValidationsExtender to access the api
- lodash (not bundled)
- knockout (not bundled)
- promiz (bundled in)
- loglevel (bundled in)
Html: (Using knockout-punches for css bindings, better syntax!)
<form data-bind="submit: performRegistration">
<fieldset data-bind="with: registration">
<div data-bind="with: product">
<div data-bind="css.has-error: name.isntValid()" class="form-group">
<input type="text" data-bind="value: name" placeholder="Product Name" class="form-control"/><span data-bind="visible: name.isntValid, text: name.joinedErrors(' / ')" class="help-block"></span>
</div>
</div>
<div data-bind="with: consumer">
<div data-bind="css.has-error: name.isntValid()" class="form-group">
<input type="text" data-bind="value: name" placeholder="Consumer Name" class="form-control"/><span data-bind="visible: name.isntValid, text: name.joinedErrors(' / ')" class="help-block"></span>
</div>
</div>
<button type="submit">Submit Registration</button>
</fieldset>
</form>
Javascript:
var Consumer = (function() {
function Consumer() {
this.name = ko.observable().extend({
validations: {
required: {
message: "Please, inform your name!"
}
}
});
}
return Consumer;
})();
var Product = (function() {
function Product() {
this.name = ko.observable().extend({
validations: {
required: {
message: "Product name is required!!"
}
}
});
}
return Product;
})();
var Registration = (function() {
function Registration() {
this.product = new Product();
this.consumer = new Consumer();
}
return Registration;
})();
var RegistrationViewModel = (function() {
function RegistrationViewModel() {
this.registration = ko.observable(new Registration()).extend({
validations: {}
});
// no validations are need for registration
// children control their own validations
}
RegistrationViewModel.prototype.performRegistration = function() {
return this.registration.validate(function(isValid) {
if (!isValid) {
return alert("hey, please fill all fields");
}
alert("everything is good, done");
this.registration(new Registration());
});
};
return RegistrationViewModel;
})();
var registrationViewModel = new RegistrationViewModel();
ko.applyBindings(registration);
Coffee-script:
class Consumer
constructor:()->
@name = ko.observable().extend
validations:
required:
message: "Please, inform your name!"
class Product
constructor:()->
@name = ko.observable().extend
validations:
required:
message: "Product name is required!!"
class Registration
constructor:()->
@product = new Product()
@consumer = new Consumer()
class RegistrationViewModel
constructor:()->
@registration = ko.observable(new Registration()).extend({validations:{}})
# no validations are need for registration
# children control their own validations
performRegistration:()->
@registration.validate (isValid)->
if !isValid then return alert("hey, please fill all fields")
alert("everything is good, done")
@registration(new Registration())
registrationViewModel = new RegistrationViewModel()
ko.applyBindings(registration)
Each knockout object can have:
- calculated errors
- errors that are calculated based on the given validation descriptions
- manual errors
- errors added manually to objects
- children errors
- errors that are resolved based on observables that are contained into the current one.
- if the current is an observable array, all errors contained in objects inside array will be resolved.
- algorithm always goes down if the current object is an array/object, and tries to find observables that use
validations extender
.
All errors are either observable/computable. So they are updated instantly if the object is validated
or is in a live
mode.
All errors are simple string
.
You can override the default error message by passing as a validation option in your field.
-
observable.getOwnCalculatedErrors() # observable array
-
observable.getOwnManualErrors() # observable array
-
observable.getOwnErrors() # computed
-
observable.hasOwnErrors() # computed
-
observable.getChildrenCalculatedErrors() # computed
-
observable.getChildrenManualErrors() # computed
-
observable.getChildrenErrors() # computed
-
observable.getAllCalculatedErrors() # computed
-
observable.getAllManualErrors() # computed
-
observable.getAllErrors() # computed
-
observable.isValid() # computed
-
observable.isntValid() # computed
-
observable.errors() # alias to getAllErrors
-
observable.joinedErrors(separator) # returns a computed
-
observable.validate(options, callback) ASYNC
- performs the validation to the current object and its
children
. - callback returns boolean determining if its valid or not
- options available:
- reset # if true, it will reset all current errors
- validateChildren # if false, it wont validate children
- performs the validation to the current object and its
-
observable.resetValidation()
-
observable.hasValidation(name)
- returns computed that returns true if the observable contains that validation
-
observable.validation(name, options)
- adds a new validation to observable
- if its live, it should trigger a new validation
-
observable.removeValidation(name)
- removes validation
-
observable.setValidations(rules)
- replaces all validations with new object definition with rules
- validation
- only validates if method
validate
is run
- only validates if method
- validationLive
- validates when something changes
- validationAlwaysLive
- validates since the start of the object lifecycle, and when something changes.
You must register validations in order for the extender
to use them.
The validations you register are an object that maps a validationName
to a validationFunction
.
validationFunction
returns a boolean, receives a singledata
parameter, wheredata
contains:- value (the actual value to validate)
- validationOptions (the options configured for this observable/validation by you)
- parent (parent observable that called the validate method)
- container (object that contains the current observable being evaluated.)
- Eg: if you had an observableArray, that contains objects, that have a field observable, you could access the parent observableArray and the container object to validate that field.
koValidations = require 'knockout-validations-extender'
# or the global variable knockoutValidationsExtender
koValidation.registerValidationMethods
required:(data)-> return data.value != null
Async validations must have async
flag specified when the validation is being registered.
Callback should be called with boolean value.
koValidation.registerValidationMethods
required:
async: true
fn: (data, callback)->
callback(data.value != null)
a) Can be a simple function
koValidation.registerValidationMethods
required:(data)-> return data.value != null
b) Can be an object
required:
async: true
fn: (data, callback)->
callback(data.value != null)
defaultMessage: "Field should be required!"
If you wish to translate the error messages, you can give a function to koValidation.
koValidation.setTranslator (message, ruleOptions)->
return message.replace('{{max}}', ruleOptions.max)