Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions can-validate/can-validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@
*
*/

import can from 'can';
import ns from 'can-util/namespace';
import Construct from 'can-construct';
import canDev from 'can-util/js/dev/';

// add methods to can
var Validate = can.Construct.extend({
var Validate = Construct.extend({

/*
* @description The current validator ID to use when can.validate methods are called.
Expand Down Expand Up @@ -96,7 +98,7 @@ var Validate = can.Construct.extend({
isValid: function () {
//!steal-remove-start
if (!this._validatorId) {
can.dev.warn('A validator library is required for can.validate to work properly.');
canDev.warn('A validator library is required for can.validate to work properly.');
}
//!steal-remove-end
return this.validator().isValid.apply(this, arguments);
Expand All @@ -118,7 +120,7 @@ var Validate = can.Construct.extend({
once: function () {
//!steal-remove-start
if (!this._validatorId) {
can.dev.warn('A validator library is required for can.validate to work properly.');
canDev.warn('A validator library is required for can.validate to work properly.');
}
//!steal-remove-end
return this.validator().once.apply(this, arguments);
Expand All @@ -139,16 +141,16 @@ var Validate = can.Construct.extend({
var validateArgs = arguments;
//!steal-remove-start
if (!this._validatorId) {
can.dev.warn('A validator library is required for can.validate to work properly.');
canDev.warn('A validator library is required for can.validate to work properly.');
}
if (typeof arguments[0] !== 'object') {
can.dev.warn('Attempting to pass single value to validate, use can.validator.once instead.');
canDev.warn('Attempting to pass single value to validate, use can.validator.once instead.');
}
//!steal-remove-end
return this.validator().validate.apply(this, validateArgs);
}
}, {});

can.validate = Validate;
ns.validate = Validate;

export default can;
export default Validate;
25 changes: 14 additions & 11 deletions can-validate/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</head>
<body>
<div id="app" class="container">
<script src="../../node_modules/steal/steal.js" main="can/view/autorender/"></script>
<script src="../../node_modules/steal/steal.js" main="can-view-autorender"></script>
<script type='text/stache' id="demo" can-autorender>
<h1>can.validate Demo</h1>

Expand All @@ -31,16 +31,16 @@ <h3 class="panel-title">Validation Test</h3>
<form>
<label for="test1">MyVal <span class="text-danger"></span></label>
<div class="input-group" {{data 'field' 'myVal'}}>
<input class="form-control" id="test1" type="text" can-value="myVal">
<input class="form-control" id="test1" type="text" {($value)}="myVal">
<span class="input-group-btn">
<button type="button" class="btn btn-default" can-click="validateField">Validate</button>
<button type="button" class="btn btn-default" ($click)="validateField">Validate</button>
</span>
</div>
<label for="test2">MyNum <span class="text-danger"></span></label>
<div class="input-group" {{data 'field' 'myNum'}}>
<input class="form-control" id="test2" type="text" can-value="myNum">
<input class="form-control" id="test2" type="text" {($value)}="myNum">
<span class="input-group-btn">
<button type="button" class="btn btn-default" can-click="validateField">Validate</button>
<button type="button" class="btn btn-default" ($click)="validateField">Validate</button>
</span>
</div>
</form>
Expand All @@ -50,7 +50,9 @@ <h3 class="panel-title">Validation Test</h3>
</script>
</div>
<script type='text/javascript'>
steal('can','can-validate/', 'can-validate/shims/validatejs.shim', function(can){
steal('jquery/dist/jquery.js', 'can-validate/', 'can-view-model', 'can-util/dom/data/', 'can-validate/shims/validatejs.shim', 'can-stache-bindings', function($, canValidate, setViewModel, domData){
window.getViewModel = setViewModel;
canValidate = canValidate.default;
var validations = {
myVal: {
required: true,
Expand All @@ -67,16 +69,17 @@ <h3 class="panel-title">Validation Test</h3>
}
};

can.$('#demo').viewModel({
setViewModel(document.getElementById('demo'), {
myVal: 'testing testing',
myNum: 100,
errors: [],
validateField: function (ctx, $el) {
validateField: function (ctx, el) {
var $el = $(el);
var $parent = $el.parents('.input-group'),
$label = can.$('label[for=' + $parent.find('.form-control').attr('id') + ']'),
val = $parent.data('field');
$label = $('label[for=' + $parent.find('.form-control').attr('id') + ']'),
val = domData.get.call($parent[0], 'field');

var errors = can.validate.once(this.attr(val), validations[val], 'myObjIsAwesome');
var errors = canValidate.once(this.attr(val), validations[val], 'myObjIsAwesome');
if (errors) {
$parent.addClass('has-error');
$label.find('.text-danger').text(errors[0]);
Expand Down
19 changes: 9 additions & 10 deletions can-validate/map/validate/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</head>
<body>
<div id="app" class="container">
<script src="../../../node_modules/steal/steal.js" main="can/view/autorender/"></script>
<script src="../../../node_modules/steal/steal.js" main="can-view-autorender/"></script>
<script type='text/stache' id="demo" can-autorender>
<h1>can.Map Validate Plugin Demo</h1>

Expand All @@ -32,19 +32,19 @@ <h3 class="panel-title">Validation Test</h3>
In the following examples, this happens when the field&rsquo;s value changes.</p>
<div class="form-group">
<label for="test1">MyVal required?</label>
<input class="form-control" id="test" type="checkbox" can-value="myMap.isRequired">
<input class="form-control" id="test" type="checkbox" {($value)}="myMap.isRequired">
</div>
<div class="form-group">
<label for="test1">MyVal</label>
<input class="form-control" id="test1" type="text" can-value="myMap.myVal">
<input class="form-control" id="test1" type="text" {($value)}="myMap.myVal">
</div>
<div class="form-group">
<label for="test2">MyNum</label>
<input class="form-control" id="test2" type="text" can-value="myMap.myNum">
<input class="form-control" id="test2" type="text" {($value)}="myMap.myNum">
</div>
<div class="input-group">
<p>You can also validate all properties at once</p>
<button type="button" class="btn btn-primary" can-click="doValidate">Validate All</button>
<button type="button" class="btn btn-primary" ($click)="doValidate">Validate All</button>
</div>
</div>
<ul class="list-group">
Expand All @@ -62,10 +62,9 @@ <h3 class="panel-title">Validation Test</h3>
</script>
</div>
<script type='text/javascript'>
steal.import('can', 'can-validate', 'can/map/define/', 'can-validate/map/validate/', 'can-validate/shims/validatejs.shim')
.then(function(modules){
var can = modules[0];
var TestMap = can.Map.extend({
steal('can-map', 'can-validate', 'can-view-model', 'can-map-define', 'can-validate/map/validate/', 'can-validate/shims/validatejs.shim', 'can-stache-bindings',
function(canMap, canValidate, setViewModel){
var TestMap = canMap.extend({
define: {
myNum: {
value: 'heyo',
Expand Down Expand Up @@ -93,7 +92,7 @@ <h3 class="panel-title">Validation Test</h3>
}
});

can.$('#demo').viewModel({
setViewModel(document.getElementById('demo'), {
myMap: new TestMap({isRequired: true}),
myFailMap: new TestMap({testString: 'hello'}),
doValidate: function () {
Expand Down
49 changes: 27 additions & 22 deletions can-validate/map/validate/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,14 @@
*
*/

import can from 'can';
import 'can-validate/can-validate';

var proto = can.Map.prototype;
import canMap from 'can-map';
import canCompute from 'can-compute';
import canValidate from 'can-validate/can-validate';
import canEach from 'can-util/js/each/';
import isEmptyObject from 'can-util/js/is-empty-object/';
import deepAssign from 'can-util/js/deep-assign/';

var proto = canMap.prototype;
var oldSet = proto.__set;
var ErrorsObj;
var defaultValidationOpts;
Expand All @@ -70,7 +74,7 @@ var resolveComputes = function (itemObj, opts) {
var processedObj = {};

// Loop through each validation option
can.each(opts, function (item, key) {
canEach(opts, function (item, key) {
var actualOpts = item;
if (typeof item === 'function') {
// create compute and add it to computes array
Expand Down Expand Up @@ -102,9 +106,9 @@ var getPropDefineBehavior = function (behavior, attr, define) {
};

// Default Map for errors object. Useful to add instance helpers
ErrorsObj = can.Map.extend({}, {
ErrorsObj = canMap.extend({}, {
hasErrors: function () {
return !can.isEmptyObject(this.attr());
return !isEmptyObject(this.attr());
}
});

Expand Down Expand Up @@ -134,12 +138,12 @@ var initProperty = function (key, value) {
mapValidateCache = getValidateFromCache.call(this);

// If validate options don't exist in cache for current prop, create them
if (mapValidateCache[key] && !can.isEmptyObject(mapValidateCache[key])) {
if (mapValidateCache[key] && !isEmptyObject(mapValidateCache[key])) {
validateOpts = mapValidateCache[key];
propIniting = false;
} else {
// Copy current prop's validation properties to cache
validateOpts = can.extend({}, getPropDefineBehavior('validate', key, this.define));
validateOpts = deepAssign({}, getPropDefineBehavior('validate', key, this.define));
// Need to build computes in the next step
propIniting = true;
}
Expand All @@ -148,7 +152,7 @@ var initProperty = function (key, value) {
if (typeof validateOpts !== 'undefined') {
//create validation computes only when initing the map
if (propIniting) {
validateOpts = can.extend({},
validateOpts = deepAssign({},
defaultValidationOpts,
validateOpts,
// Find any functions, converts them to computes and returns
Expand Down Expand Up @@ -177,11 +181,11 @@ proto.init = function () {
oldInit.apply(this, arguments);
}
};
can.extend(can.Map.prototype, {
deepAssign(canMap.prototype, {
_initValidation: function () {
var self = this;
var validateCache = getValidateFromCache.call(this);
can.each(this.define, function (props, key) {
canEach(this.define, function (props, key) {
if (props.validate && !validateCache[key]) {
initProperty.call(self, key, self[key]);
}
Expand Down Expand Up @@ -211,18 +215,18 @@ can.extend(can.Map.prototype, {
var self = this;

// Loop through validate options
can.each(this.define, function (value, key) {
canEach(this.define, function (value, key) {
if (value.validate) {
processedOpts[key] = resolveComputes({key: key, value: self.attr(key)}, validateOpts[key]);
}
});
var errors = can.validate.validate(this.serialize(), processedOpts);
var errors = canValidate.validate(this.serialize(), processedOpts);

// Process errors if we got them
// TODO: This creates a new instance every time.
this.attr('errors', new ErrorsObj(errors));

return can.isEmptyObject(errors);
return isEmptyObject(errors);
},
/**
* @function _validateOne Validate One
Expand All @@ -235,16 +239,17 @@ can.extend(can.Map.prototype, {
*
* @param {object} item A key/value object
* @param {object} opts Object that contains validation config.
+ @param {object} otherItems Object that contains other attributes in the map
* @return {boolean} True if method found that the property can be saved; if
* validation fails and the property must validate (`mustValidate` property),
* this will be `false`.
*/
_validateOne: function (item, opts) {
_validateOne: function (item, opts, otherItems) {
var errors;
var allowSet = true;

// run validation
errors = can.validate.once(item.value, can.extend({}, opts), item.key);
errors = canValidate.once(item.value, deepAssign({}, opts), item.key, otherItems);

// Process errors if we got them
if (errors && errors.length > 0) {
Expand Down Expand Up @@ -287,11 +292,11 @@ can.extend(can.Map.prototype, {
var self = this;

// Loop through each validation option
can.each(opts, function (item, key) {
canEach(opts, function (item, key) {
processedObj[key] = item;
if (typeof item === 'function') {
// create compute and add it to computes array
var compute = can.compute(can.proxy(item, self));
var compute = canCompute(Function.prototype.bind.call(item, self));
computes.push({key: key, compute: compute});
processedObj[key] = compute;
}
Expand All @@ -300,10 +305,10 @@ can.extend(can.Map.prototype, {
// Using the computes array, create necessary listeners
// We do this afterwards instead of inline so we can have access
// to the final set of validation options.
can.each(computes, function (item) {
canEach(computes, function (item) {
item.compute.bind('change', function () {
itemObj.value = self.attr(itemObj.key);
self._validateOne(itemObj, processedObj);
self._validateOne(itemObj, processedObj, self.attr());
});
});

Expand All @@ -325,7 +330,7 @@ proto.__set = function (prop, value, current, success, error) {
// If validate opts are set and initing, validate properties only if validateOnInit is true
if ((validateOpts && !mapIniting) || (validateOpts && mapIniting && validateOpts.validateOnInit)) {
// Validate item
allowSet = this._validateOne({key: prop, value: value}, validateOpts);
allowSet = this._validateOne({key: prop, value: value}, validateOpts, this.attr());
}
}

Expand Down
11 changes: 6 additions & 5 deletions can-validate/map/validate/validate.test.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
/* jshint asi: false */
import can from 'can';
import 'can/map/define/';
import canMap from 'can-map';
import 'can-map-define';
import 'can-validate';
import 'can-validate/map/validate/';
import 'can-validate/shims/validatejs.shim';
import isEmptyObject from 'can-util/js/is-empty-object/';
import 'chai';
import 'steal-mocha';
var expect = chai.expect;
var validatedMap;
var secondaryMap;

var ValidatedMap = can.Map.extend({
var ValidatedMap = canMap.extend({
define: {
myNumber: {
value: 100,
Expand Down Expand Up @@ -40,7 +41,7 @@ describe('Validate can.Map define plugin', function () {
validatedMap = new ValidatedMap();
});
it('does not validate', function () {
expect(can.isEmptyObject(validatedMap.errors)).to.equal(true);
expect(isEmptyObject(validatedMap.errors)).to.equal(true);
});
});
});
Expand Down Expand Up @@ -95,7 +96,7 @@ describe('Validate can.Map define plugin', function () {
});
it('control map validates successfully', function () {
secondaryMap.attr('computedProp', '');
expect(can.isEmptyObject(secondaryMap.attr('errors'))).to.equal(true);
expect(isEmptyObject(secondaryMap.attr('errors'))).to.equal(true);
});
it('other map validates, sets error', function () {
validatedMap.attr('computedProp', '');
Expand Down
Loading