From 5c5deafb2f37eb1f9333fdd3321bd2391e21d14d Mon Sep 17 00:00:00 2001 From: janvanderhaegen Date: Sat, 25 Apr 2015 20:50:29 -0600 Subject: [PATCH 1/2] feat(clear): validation.result.clear() resets validation result Calling .clear() on the validationResult (validation.result) will reset the entire validation result to non-dirty and valid. Fixes #44 --- dist/amd/index.js | 2 +- .../validation/validate-custom-attribute.js | 7 ++- dist/amd/validation/validation-result.js | 55 ++++++++++++------ dist/amd/validation/validation.js | 5 +- dist/commonjs/index.js | 2 +- .../validation/validate-custom-attribute.js | 7 ++- .../validation/validation-group-builder.js | 2 +- .../validation/validation-property.js | 2 +- dist/commonjs/validation/validation-result.js | 53 +++++++++++------ dist/commonjs/validation/validation.js | 7 ++- dist/es6/validation/validation-result.js | 27 +++++++-- .../validation/validate-custom-attribute.js | 7 ++- dist/system/validation/validation-result.js | 55 ++++++++++++------ dist/system/validation/validation.js | 5 +- src/validation/validation-result.js | 27 +++++++-- test/expectations.js | 2 + test/validation-api.spec.js | 57 +++++++++++++++++++ 17 files changed, 237 insertions(+), 85 deletions(-) diff --git a/dist/amd/index.js b/dist/amd/index.js index fcab3d57..6500b69f 100644 --- a/dist/amd/index.js +++ b/dist/amd/index.js @@ -1,7 +1,7 @@ define(['exports', './validation/validation-config', './validation/validation', './validation/utilities', './validation/validation-locale', './validation/validation-result', './validation/validation-rules', './validation/validate-custom-attribute', './validation/validate-custom-attribute-view-strategy'], function (exports, _validationValidationConfig, _validationValidation, _validationUtilities, _validationValidationLocale, _validationValidationResult, _validationValidationRules, _validationValidateCustomAttribute, _validationValidateCustomAttributeViewStrategy) { 'use strict'; - var _interopRequireWildcard = function (obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }; + var _interopRequireWildcard = function (obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (typeof obj === 'object' && obj !== null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }; var _defaults = function (obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; }; diff --git a/dist/amd/validation/validate-custom-attribute.js b/dist/amd/validation/validate-custom-attribute.js index a5515dd3..ea9d3b5f 100644 --- a/dist/amd/validation/validate-custom-attribute.js +++ b/dist/amd/validation/validate-custom-attribute.js @@ -18,7 +18,9 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-templating'], functi this.viewStrategy = null; } - _createClass(ValidateCustomAttribute, [{ + var _ValidateCustomAttribute = ValidateCustomAttribute; + + _createClass(_ValidateCustomAttribute, [{ key: 'valueChanged', value: function valueChanged(newValue) { if (this.value === null || this.value === undefined) { @@ -58,9 +60,8 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-templating'], functi } }]); - var _ValidateCustomAttribute = ValidateCustomAttribute; - ValidateCustomAttribute = _aureliaTemplating.customAttribute('validate')(ValidateCustomAttribute) || ValidateCustomAttribute; ValidateCustomAttribute = _aureliaDependencyInjection.inject(Element)(ValidateCustomAttribute) || ValidateCustomAttribute; + ValidateCustomAttribute = _aureliaTemplating.customAttribute('validate')(ValidateCustomAttribute) || ValidateCustomAttribute; return ValidateCustomAttribute; })(); diff --git a/dist/amd/validation/validation-result.js b/dist/amd/validation/validation-result.js index 796e1b1a..59c07bf9 100644 --- a/dist/amd/validation/validation-result.js +++ b/dist/amd/validation/validation-result.js @@ -1,11 +1,11 @@ -define(["exports"], function (exports) { - "use strict"; +define(['exports'], function (exports) { + 'use strict'; - var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }; - var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); - Object.defineProperty(exports, "__esModule", { + Object.defineProperty(exports, '__esModule', { value: true }); @@ -18,7 +18,7 @@ define(["exports"], function (exports) { } _createClass(ValidationResult, [{ - key: "addProperty", + key: 'addProperty', value: function addProperty(name) { if (!this.properties[name]) { this.properties[name] = new ValidationResultProperty(this); @@ -26,7 +26,7 @@ define(["exports"], function (exports) { return this.properties[name]; } }, { - key: "checkValidity", + key: 'checkValidity', value: function checkValidity() { for (var propertyName in this.properties) { if (!this.properties[propertyName].isValid) { @@ -36,6 +36,14 @@ define(["exports"], function (exports) { } this.isValid = true; } + }, { + key: 'clear', + value: function clear() { + for (var propertyName in this.properties) { + this.properties[propertyName].clear(); + } + this.isValid = true; + } }]); return ValidationResult; @@ -48,21 +56,35 @@ define(["exports"], function (exports) { _classCallCheck(this, ValidationResultProperty); this.group = group; - this.isValid = true; - this.isDirty = false; - this.message = null; - this.failingRule = null; this.onValidateCallbacks = []; - this.latestValue = null; + this.clear(); } _createClass(ValidationResultProperty, [{ - key: "onValidate", + key: 'clear', + value: function clear() { + this.isValid = true; + this.isDirty = false; + this.message = ''; + this.failingRule = null; + this.latestValue = null; + this.notifyObserversOfChange(); + } + }, { + key: 'onValidate', value: function onValidate(onValidateCallback) { this.onValidateCallbacks.push(onValidateCallback); } }, { - key: "setValidity", + key: 'notifyObserversOfChange', + value: function notifyObserversOfChange() { + for (var i = 0; i < this.onValidateCallbacks.length; i++) { + var callback = this.onValidateCallbacks[i]; + callback(this); + } + } + }, { + key: 'setValidity', value: function setValidity(validationResponse, shouldBeDirty) { var notifyObservers = !this.isDirty && shouldBeDirty || this.isValid !== validationResponse.isValid || this.message !== validationResponse.message; @@ -74,10 +96,7 @@ define(["exports"], function (exports) { if (this.isValid !== this.group.isValid) this.group.checkValidity(); if (notifyObservers) { - for (var i = 0; i < this.onValidateCallbacks.length; i++) { - var callback = this.onValidateCallbacks[i]; - callback(this); - } + this.notifyObserversOfChange(); } } }]); diff --git a/dist/amd/validation/validation.js b/dist/amd/validation/validation.js index 50e945ed..1b351500 100644 --- a/dist/amd/validation/validation.js +++ b/dist/amd/validation/validation.js @@ -17,7 +17,9 @@ define(['exports', 'aurelia-binding', '../validation/validation-rules', '../vali this.config = validationConfig ? validationConfig : Validation.defaults; } - _createClass(Validation, [{ + var _Validation = Validation; + + _createClass(_Validation, [{ key: 'on', value: function on(subject, configCallback) { var conf = new _validationValidationConfig.ValidationConfig(this.config); @@ -28,7 +30,6 @@ define(['exports', 'aurelia-binding', '../validation/validation-rules', '../vali } }]); - var _Validation = Validation; Validation = _aureliaDependencyInjection.inject(_aureliaBinding.ObserverLocator)(Validation) || Validation; return Validation; })(); diff --git a/dist/commonjs/index.js b/dist/commonjs/index.js index 794b8a4f..326b02b7 100644 --- a/dist/commonjs/index.js +++ b/dist/commonjs/index.js @@ -1,6 +1,6 @@ 'use strict'; -var _interopRequireWildcard = function (obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }; +var _interopRequireWildcard = function (obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (typeof obj === 'object' && obj !== null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }; var _defaults = function (obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; }; diff --git a/dist/commonjs/validation/validate-custom-attribute.js b/dist/commonjs/validation/validate-custom-attribute.js index 0930147b..3983356a 100644 --- a/dist/commonjs/validation/validate-custom-attribute.js +++ b/dist/commonjs/validation/validate-custom-attribute.js @@ -21,7 +21,9 @@ var ValidateCustomAttribute = (function () { this.viewStrategy = null; } - _createClass(ValidateCustomAttribute, [{ + var _ValidateCustomAttribute = ValidateCustomAttribute; + + _createClass(_ValidateCustomAttribute, [{ key: 'valueChanged', value: function valueChanged(newValue) { if (this.value === null || this.value === undefined) { @@ -61,9 +63,8 @@ var ValidateCustomAttribute = (function () { } }]); - var _ValidateCustomAttribute = ValidateCustomAttribute; - ValidateCustomAttribute = _customAttribute.customAttribute('validate')(ValidateCustomAttribute) || ValidateCustomAttribute; ValidateCustomAttribute = _inject.inject(Element)(ValidateCustomAttribute) || ValidateCustomAttribute; + ValidateCustomAttribute = _customAttribute.customAttribute('validate')(ValidateCustomAttribute) || ValidateCustomAttribute; return ValidateCustomAttribute; })(); diff --git a/dist/commonjs/validation/validation-group-builder.js b/dist/commonjs/validation/validation-group-builder.js index 28890348..98a6386d 100644 --- a/dist/commonjs/validation/validation-group-builder.js +++ b/dist/commonjs/validation/validation-group-builder.js @@ -1,6 +1,6 @@ 'use strict'; -var _interopRequireWildcard = function (obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }; +var _interopRequireWildcard = function (obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (typeof obj === 'object' && obj !== null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }; var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }; diff --git a/dist/commonjs/validation/validation-property.js b/dist/commonjs/validation/validation-property.js index f55781da..52a881b8 100644 --- a/dist/commonjs/validation/validation-property.js +++ b/dist/commonjs/validation/validation-property.js @@ -1,6 +1,6 @@ 'use strict'; -var _interopRequireWildcard = function (obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }; +var _interopRequireWildcard = function (obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (typeof obj === 'object' && obj !== null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }; var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }; diff --git a/dist/commonjs/validation/validation-result.js b/dist/commonjs/validation/validation-result.js index b743bbc5..3e8b24da 100644 --- a/dist/commonjs/validation/validation-result.js +++ b/dist/commonjs/validation/validation-result.js @@ -1,10 +1,10 @@ -"use strict"; +'use strict'; -var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }; -var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); -Object.defineProperty(exports, "__esModule", { +Object.defineProperty(exports, '__esModule', { value: true }); @@ -17,7 +17,7 @@ var ValidationResult = (function () { } _createClass(ValidationResult, [{ - key: "addProperty", + key: 'addProperty', value: function addProperty(name) { if (!this.properties[name]) { this.properties[name] = new ValidationResultProperty(this); @@ -25,7 +25,7 @@ var ValidationResult = (function () { return this.properties[name]; } }, { - key: "checkValidity", + key: 'checkValidity', value: function checkValidity() { for (var propertyName in this.properties) { if (!this.properties[propertyName].isValid) { @@ -35,6 +35,14 @@ var ValidationResult = (function () { } this.isValid = true; } + }, { + key: 'clear', + value: function clear() { + for (var propertyName in this.properties) { + this.properties[propertyName].clear(); + } + this.isValid = true; + } }]); return ValidationResult; @@ -47,21 +55,35 @@ var ValidationResultProperty = (function () { _classCallCheck(this, ValidationResultProperty); this.group = group; - this.isValid = true; - this.isDirty = false; - this.message = null; - this.failingRule = null; this.onValidateCallbacks = []; - this.latestValue = null; + this.clear(); } _createClass(ValidationResultProperty, [{ - key: "onValidate", + key: 'clear', + value: function clear() { + this.isValid = true; + this.isDirty = false; + this.message = ''; + this.failingRule = null; + this.latestValue = null; + this.notifyObserversOfChange(); + } + }, { + key: 'onValidate', value: function onValidate(onValidateCallback) { this.onValidateCallbacks.push(onValidateCallback); } }, { - key: "setValidity", + key: 'notifyObserversOfChange', + value: function notifyObserversOfChange() { + for (var i = 0; i < this.onValidateCallbacks.length; i++) { + var callback = this.onValidateCallbacks[i]; + callback(this); + } + } + }, { + key: 'setValidity', value: function setValidity(validationResponse, shouldBeDirty) { var notifyObservers = !this.isDirty && shouldBeDirty || this.isValid !== validationResponse.isValid || this.message !== validationResponse.message; @@ -73,10 +95,7 @@ var ValidationResultProperty = (function () { if (this.isValid !== this.group.isValid) this.group.checkValidity(); if (notifyObservers) { - for (var i = 0; i < this.onValidateCallbacks.length; i++) { - var callback = this.onValidateCallbacks[i]; - callback(this); - } + this.notifyObserversOfChange(); } } }]); diff --git a/dist/commonjs/validation/validation.js b/dist/commonjs/validation/validation.js index a204c086..7bc32791 100644 --- a/dist/commonjs/validation/validation.js +++ b/dist/commonjs/validation/validation.js @@ -1,6 +1,6 @@ 'use strict'; -var _interopRequireWildcard = function (obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }; +var _interopRequireWildcard = function (obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (typeof obj === 'object' && obj !== null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }; var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }; @@ -34,7 +34,9 @@ var Validation = (function () { this.config = validationConfig ? validationConfig : Validation.defaults; } - _createClass(Validation, [{ + var _Validation = Validation; + + _createClass(_Validation, [{ key: 'on', value: function on(subject, configCallback) { var conf = new _ValidationConfig.ValidationConfig(this.config); @@ -45,7 +47,6 @@ var Validation = (function () { } }]); - var _Validation = Validation; Validation = _inject.inject(_ObserverLocator.ObserverLocator)(Validation) || Validation; return Validation; })(); diff --git a/dist/es6/validation/validation-result.js b/dist/es6/validation/validation-result.js index 9512217b..956aec5f 100644 --- a/dist/es6/validation/validation-result.js +++ b/dist/es6/validation/validation-result.js @@ -20,23 +20,41 @@ export class ValidationResult { } this.isValid = true; } + clear() { + for (let propertyName in this.properties) { + this.properties[propertyName].clear(); + } + this.isValid = true; + } } export class ValidationResultProperty { constructor(group) { this.group = group; + this.onValidateCallbacks = []; + this.clear(); + } + + clear(){ this.isValid = true; this.isDirty = false; - this.message = null; + this.message = ''; this.failingRule = null; - this.onValidateCallbacks = []; this.latestValue = null; + this.notifyObserversOfChange(); } onValidate(onValidateCallback) { this.onValidateCallbacks.push(onValidateCallback); } + notifyObserversOfChange(){ + for (var i = 0; i < this.onValidateCallbacks.length; i++) { + var callback = this.onValidateCallbacks[i]; + callback(this); + } + } + setValidity(validationResponse, shouldBeDirty) { var notifyObservers = (!this.isDirty && shouldBeDirty) || (this.isValid !== validationResponse.isValid) @@ -53,10 +71,7 @@ export class ValidationResultProperty { this.group.checkValidity(); if (notifyObservers) { - for (var i = 0; i < this.onValidateCallbacks.length; i++) { - var callback = this.onValidateCallbacks[i]; - callback(this); - } + this.notifyObserversOfChange(); } } } diff --git a/dist/system/validation/validate-custom-attribute.js b/dist/system/validation/validate-custom-attribute.js index 13ca583a..482f0ee0 100644 --- a/dist/system/validation/validate-custom-attribute.js +++ b/dist/system/validation/validate-custom-attribute.js @@ -24,7 +24,9 @@ System.register(['aurelia-dependency-injection', 'aurelia-templating'], function this.viewStrategy = null; } - _createClass(ValidateCustomAttribute, [{ + var _ValidateCustomAttribute = ValidateCustomAttribute; + + _createClass(_ValidateCustomAttribute, [{ key: 'valueChanged', value: function valueChanged(newValue) { if (this.value === null || this.value === undefined) { @@ -64,9 +66,8 @@ System.register(['aurelia-dependency-injection', 'aurelia-templating'], function } }]); - var _ValidateCustomAttribute = ValidateCustomAttribute; - ValidateCustomAttribute = customAttribute('validate')(ValidateCustomAttribute) || ValidateCustomAttribute; ValidateCustomAttribute = inject(Element)(ValidateCustomAttribute) || ValidateCustomAttribute; + ValidateCustomAttribute = customAttribute('validate')(ValidateCustomAttribute) || ValidateCustomAttribute; return ValidateCustomAttribute; })(); diff --git a/dist/system/validation/validation-result.js b/dist/system/validation/validation-result.js index 48287c5d..cb244dcb 100644 --- a/dist/system/validation/validation-result.js +++ b/dist/system/validation/validation-result.js @@ -4,11 +4,11 @@ System.register([], function (_export) { return { setters: [], execute: function () { - "use strict"; + 'use strict'; - _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }; - _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); ValidationResult = (function () { function ValidationResult() { @@ -19,7 +19,7 @@ System.register([], function (_export) { } _createClass(ValidationResult, [{ - key: "addProperty", + key: 'addProperty', value: function addProperty(name) { if (!this.properties[name]) { this.properties[name] = new ValidationResultProperty(this); @@ -27,7 +27,7 @@ System.register([], function (_export) { return this.properties[name]; } }, { - key: "checkValidity", + key: 'checkValidity', value: function checkValidity() { for (var propertyName in this.properties) { if (!this.properties[propertyName].isValid) { @@ -37,33 +37,55 @@ System.register([], function (_export) { } this.isValid = true; } + }, { + key: 'clear', + value: function clear() { + for (var propertyName in this.properties) { + this.properties[propertyName].clear(); + } + this.isValid = true; + } }]); return ValidationResult; })(); - _export("ValidationResult", ValidationResult); + _export('ValidationResult', ValidationResult); ValidationResultProperty = (function () { function ValidationResultProperty(group) { _classCallCheck(this, ValidationResultProperty); this.group = group; - this.isValid = true; - this.isDirty = false; - this.message = null; - this.failingRule = null; this.onValidateCallbacks = []; - this.latestValue = null; + this.clear(); } _createClass(ValidationResultProperty, [{ - key: "onValidate", + key: 'clear', + value: function clear() { + this.isValid = true; + this.isDirty = false; + this.message = ''; + this.failingRule = null; + this.latestValue = null; + this.notifyObserversOfChange(); + } + }, { + key: 'onValidate', value: function onValidate(onValidateCallback) { this.onValidateCallbacks.push(onValidateCallback); } }, { - key: "setValidity", + key: 'notifyObserversOfChange', + value: function notifyObserversOfChange() { + for (var i = 0; i < this.onValidateCallbacks.length; i++) { + var callback = this.onValidateCallbacks[i]; + callback(this); + } + } + }, { + key: 'setValidity', value: function setValidity(validationResponse, shouldBeDirty) { var notifyObservers = !this.isDirty && shouldBeDirty || this.isValid !== validationResponse.isValid || this.message !== validationResponse.message; @@ -75,10 +97,7 @@ System.register([], function (_export) { if (this.isValid !== this.group.isValid) this.group.checkValidity(); if (notifyObservers) { - for (var i = 0; i < this.onValidateCallbacks.length; i++) { - var callback = this.onValidateCallbacks[i]; - callback(this); - } + this.notifyObserversOfChange(); } } }]); @@ -86,7 +105,7 @@ System.register([], function (_export) { return ValidationResultProperty; })(); - _export("ValidationResultProperty", ValidationResultProperty); + _export('ValidationResultProperty', ValidationResultProperty); } }; }); \ No newline at end of file diff --git a/dist/system/validation/validation.js b/dist/system/validation/validation.js index d0041662..fffd2d08 100644 --- a/dist/system/validation/validation.js +++ b/dist/system/validation/validation.js @@ -30,7 +30,9 @@ System.register(['aurelia-binding', '../validation/validation-rules', '../valida this.config = validationConfig ? validationConfig : Validation.defaults; } - _createClass(Validation, [{ + var _Validation = Validation; + + _createClass(_Validation, [{ key: 'on', value: function on(subject, configCallback) { var conf = new ValidationConfig(this.config); @@ -41,7 +43,6 @@ System.register(['aurelia-binding', '../validation/validation-rules', '../valida } }]); - var _Validation = Validation; Validation = inject(ObserverLocator)(Validation) || Validation; return Validation; })(); diff --git a/src/validation/validation-result.js b/src/validation/validation-result.js index 9512217b..956aec5f 100644 --- a/src/validation/validation-result.js +++ b/src/validation/validation-result.js @@ -20,23 +20,41 @@ export class ValidationResult { } this.isValid = true; } + clear() { + for (let propertyName in this.properties) { + this.properties[propertyName].clear(); + } + this.isValid = true; + } } export class ValidationResultProperty { constructor(group) { this.group = group; + this.onValidateCallbacks = []; + this.clear(); + } + + clear(){ this.isValid = true; this.isDirty = false; - this.message = null; + this.message = ''; this.failingRule = null; - this.onValidateCallbacks = []; this.latestValue = null; + this.notifyObserversOfChange(); } onValidate(onValidateCallback) { this.onValidateCallbacks.push(onValidateCallback); } + notifyObserversOfChange(){ + for (var i = 0; i < this.onValidateCallbacks.length; i++) { + var callback = this.onValidateCallbacks[i]; + callback(this); + } + } + setValidity(validationResponse, shouldBeDirty) { var notifyObservers = (!this.isDirty && shouldBeDirty) || (this.isValid !== validationResponse.isValid) @@ -53,10 +71,7 @@ export class ValidationResultProperty { this.group.checkValidity(); if (notifyObservers) { - for (var i = 0; i < this.onValidateCallbacks.length; i++) { - var callback = this.onValidateCallbacks[i]; - callback(this); - } + this.notifyObserversOfChange(); } } } diff --git a/test/expectations.js b/test/expectations.js index b891c413..1b2bb0da 100644 --- a/test/expectations.js +++ b/test/expectations.js @@ -29,6 +29,8 @@ export class Expectations { } ) .then( (promiseResult) => { this.expect(promiseResult).toBe(shouldSucceed); + }, (failResult) => { + this.expect(failResult).toBe('assertion should not fail'); }); } }; diff --git a/test/validation-api.spec.js b/test/validation-api.spec.js index 6dd9b7fc..c46b63b2 100644 --- a/test/validation-api.spec.js +++ b/test/validation-api.spec.js @@ -247,6 +247,63 @@ describe('Some simple API tests', ()=>{ }); +describe('Some simple tests on .result', ()=>{ + it('on individual valid properties', (done) => { + var expectations = new Expectations(expect, done); + + let subject = { password : 'Abc*12345' }; + subject.validation = new Validation(new ObserverLocator(), new ValidationConfig()).on(subject) + .ensure('password').isNotEmpty().hasMinLength(8).isStrongPassword(); + + expectations.assert(subject.validation.validate(), true); + expectations.expectAsync( () => { return subject.validation.result.properties.password.isValid }).toBe(true); + expectations.expectAsync( () => { return subject.validation.result.properties.password.isDirty }).toBe(true); + expectations.expectAsync( () => { return subject.validation.result.properties.password.message }).toBe(''); + expectations.expectAsync( () => { return subject.validation.result.properties.password.failingRule }).toBe(null); + expectations.validate(); + }); + it('on individual invalid properties', (done) => { + var expectations = new Expectations(expect, done); + + let subject = { password : 'abc' }; + subject.validation = new Validation(new ObserverLocator(), new ValidationConfig()).on(subject) + .ensure('password').isNotEmpty().hasMinLength(8).isStrongPassword(); + + expectations.assert(subject.validation.validate(), false); + expectations.expectAsync( () => { return subject.validation.result.properties.password.isValid }).toBe(false); + expectations.expectAsync( () => { return subject.validation.result.properties.password.isDirty }).toBe(true); + expectations.expectAsync( () => { return subject.validation.result.properties.password.message }).toBe('needs to be at least 8 characters long'); + expectations.expectAsync( () => { return subject.validation.result.properties.password.failingRule }).toBe('MinimumLengthValidationRule'); + expectations.validate(); + }); + + it('on individual invalid properties after reset', (done) => { + var expectations = new Expectations(expect, done); + + let subject = { password : 'abc' }; + subject.validation = new Validation(new ObserverLocator(), new ValidationConfig()).on(subject) + .ensure('password').isNotEmpty().hasMinLength(8).isStrongPassword(); + + expectations.assert(subject.validation.validate(), false); + expectations.expectAsync( () => { return subject.validation.result.properties.password.isValid }).toBe(false); + expectations.expectAsync( () => { return subject.validation.result.properties.password.isDirty }).toBe(true); + expectations.expectAsync( () => { return subject.validation.result.properties.password.message }).toBe('needs to be at least 8 characters long'); + expectations.expectAsync( () => { return subject.validation.result.properties.password.failingRule }).toBe('MinimumLengthValidationRule'); + + + expectations.expectAsync(() =>{ + subject.validation.result.clear(); + return true; + }).toBe(true); + expectations.expectAsync( () => { return subject.validation.result.properties.password.isValid }).toBe(true); + expectations.expectAsync( () => { return subject.validation.result.properties.password.isDirty }).toBe(false); + expectations.expectAsync( () => { return subject.validation.result.properties.password.message }).toBe(''); + expectations.expectAsync( () => { return subject.validation.result.properties.password.failingRule }).toBe(null); + expectations.validate(); + }); + +}); + describe('Some simple configuration API tests', ()=>{ it('on computedFrom with a single dependencies', (done) => { let subject = { password : 'Abc*12345', confirmPassword : 'Abc*12345' }; From ff92803e91ded0c29855ca73f8d5169abddd3466 Mon Sep 17 00:00:00 2001 From: janvanderhaegen Date: Sat, 25 Apr 2015 21:07:27 -0600 Subject: [PATCH 2/2] fix(onValidate): onValidate would overwrite already invalid properties When an onValidate callback returns invalid for a property that was already invalid, the result got overwritten leading to weird UX. --- dist/amd/validation/validation-group.js | 16 +++++++++------- dist/commonjs/validation/validation-group.js | 16 +++++++++------- dist/es6/validation/validation-group.js | 18 ++++++++++-------- dist/system/validation/validation-group.js | 16 +++++++++------- src/validation/validation-group.js | 18 ++++++++++-------- test/on-validate.spec.js | 11 +++++++++++ 6 files changed, 58 insertions(+), 37 deletions(-) diff --git a/dist/amd/validation/validation-group.js b/dist/amd/validation/validation-group.js index b95786c2..503dc4db 100644 --- a/dist/amd/validation/validation-group.js +++ b/dist/amd/validation/validation-group.js @@ -80,14 +80,16 @@ define(['exports', '../validation/validation-group-builder', '../validation/vali resultProp.setValidity(newPropResult, true); } } else { - newPropResult.failingRule = 'onValidateCallback'; - newPropResult.isValid = false; - if (typeof result === 'string') { - newPropResult.message = result; - } else { - newPropResult.message = locale.translate(newPropResult.failingRule); + if (resultProp.isValid) { + newPropResult.failingRule = 'onValidateCallback'; + newPropResult.isValid = false; + if (typeof result === 'string') { + newPropResult.message = result; + } else { + newPropResult.message = locale.translate(newPropResult.failingRule); + } + resultProp.setValidity(newPropResult, true); } - resultProp.setValidity(newPropResult, true); } } _this2.result.checkValidity(); diff --git a/dist/commonjs/validation/validation-group.js b/dist/commonjs/validation/validation-group.js index af9305bb..889d6787 100644 --- a/dist/commonjs/validation/validation-group.js +++ b/dist/commonjs/validation/validation-group.js @@ -85,14 +85,16 @@ var ValidationGroup = (function () { resultProp.setValidity(newPropResult, true); } } else { - newPropResult.failingRule = 'onValidateCallback'; - newPropResult.isValid = false; - if (typeof result === 'string') { - newPropResult.message = result; - } else { - newPropResult.message = locale.translate(newPropResult.failingRule); + if (resultProp.isValid) { + newPropResult.failingRule = 'onValidateCallback'; + newPropResult.isValid = false; + if (typeof result === 'string') { + newPropResult.message = result; + } else { + newPropResult.message = locale.translate(newPropResult.failingRule); + } + resultProp.setValidity(newPropResult, true); } - resultProp.setValidity(newPropResult, true); } } _this2.result.checkValidity(); diff --git a/dist/es6/validation/validation-group.js b/dist/es6/validation/validation-group.js index b4e16285..c3acf330 100644 --- a/dist/es6/validation/validation-group.js +++ b/dist/es6/validation/validation-group.js @@ -69,15 +69,17 @@ export class ValidationGroup { } } else { - newPropResult.failingRule = 'onValidateCallback'; - newPropResult.isValid = false; - if (typeof(result) === 'string') { - newPropResult.message = result; - } - else { - newPropResult.message = locale.translate(newPropResult.failingRule); + if(resultProp.isValid) { + newPropResult.failingRule = 'onValidateCallback'; + newPropResult.isValid = false; + if (typeof(result) === 'string') { + newPropResult.message = result; + } + else { + newPropResult.message = locale.translate(newPropResult.failingRule); + } + resultProp.setValidity(newPropResult, true); } - resultProp.setValidity(newPropResult, true); } } this.result.checkValidity(); diff --git a/dist/system/validation/validation-group.js b/dist/system/validation/validation-group.js index ced37428..d21ae79b 100644 --- a/dist/system/validation/validation-group.js +++ b/dist/system/validation/validation-group.js @@ -87,14 +87,16 @@ System.register(['../validation/validation-group-builder', '../validation/valida resultProp.setValidity(newPropResult, true); } } else { - newPropResult.failingRule = 'onValidateCallback'; - newPropResult.isValid = false; - if (typeof result === 'string') { - newPropResult.message = result; - } else { - newPropResult.message = locale.translate(newPropResult.failingRule); + if (resultProp.isValid) { + newPropResult.failingRule = 'onValidateCallback'; + newPropResult.isValid = false; + if (typeof result === 'string') { + newPropResult.message = result; + } else { + newPropResult.message = locale.translate(newPropResult.failingRule); + } + resultProp.setValidity(newPropResult, true); } - resultProp.setValidity(newPropResult, true); } } _this2.result.checkValidity(); diff --git a/src/validation/validation-group.js b/src/validation/validation-group.js index b4e16285..c3acf330 100644 --- a/src/validation/validation-group.js +++ b/src/validation/validation-group.js @@ -69,15 +69,17 @@ export class ValidationGroup { } } else { - newPropResult.failingRule = 'onValidateCallback'; - newPropResult.isValid = false; - if (typeof(result) === 'string') { - newPropResult.message = result; - } - else { - newPropResult.message = locale.translate(newPropResult.failingRule); + if(resultProp.isValid) { + newPropResult.failingRule = 'onValidateCallback'; + newPropResult.isValid = false; + if (typeof(result) === 'string') { + newPropResult.message = result; + } + else { + newPropResult.message = locale.translate(newPropResult.failingRule); + } + resultProp.setValidity(newPropResult, true); } - resultProp.setValidity(newPropResult, true); } } this.result.checkValidity(); diff --git a/test/on-validate.spec.js b/test/on-validate.spec.js index 6cb532d6..057a2553 100644 --- a/test/on-validate.spec.js +++ b/test/on-validate.spec.js @@ -28,6 +28,7 @@ describe('Tests on onValidate callbacks', () => { expectations.assert(subject.validation.validate(), false); expectations.expectAsync(() => { return wasCalled;}).toBe(true); + expectations.expectAsync(() => { return subject.validation.result.properties.firstName.failingRule;}).toBe('MinimumLengthValidationRule'); expectations.validate(); }); @@ -84,6 +85,16 @@ describe('Tests on onValidate callbacks', () => { expectations.validate(); }); + it('should not overwrite an already failing property', (done) => { + var expectations = new Expectations(expect, done); + var subject = TestSubject.createInstance('Bob'); + subject.validation.onValidate( () => { + return {firstName : false } + }); + expectations.assert(subject.validation.validate(), false); + expectations.expectAsync(() => { return subject.validation.result.properties.firstName.failingRule;}).toBe('MinimumLengthValidationRule'); + expectations.validate(); + }); it('should correctly handle the result of the callback if it returns a promise that returns false for a property', (done) => {