From b28c9583f7fa88dd701cff1a197ecc79b4c3dc88 Mon Sep 17 00:00:00 2001 From: delixfe Date: Wed, 27 Jun 2012 15:28:57 +0200 Subject: [PATCH 1/9] Validatable observables get an additional property errorDetails which does not only contain the message but also the rule, the params and the observable itself (to have access to it on grouping). --- Src/knockout.validation.js | 21 +++++++++++-- Tests/validation-tests.js | 62 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/Src/knockout.validation.js b/Src/knockout.validation.js index 078b99cd..dc8e8051 100644 --- a/Src/knockout.validation.js +++ b/Src/knockout.validation.js @@ -588,12 +588,12 @@ msg = null, isModified = false, isValid = false; - + obsv.extend({ validatable: true }); isModified = obsv.isModified(); isValid = obsv.isValid(); - + // create a handler to correctly return an error message var errorMsgAccessor = function () { if (!config.messagesOnModified || isModified) { @@ -706,7 +706,7 @@ if (enable && !utils.isValidatable(observable)) { observable.error = null; // holds the error message, we only need one since we stop processing validators when one is invalid - + observable.errorDetails = null; // // observable.rules: // ObservableArray of Rule Contexts, where a Rule Context is simply the name of a rule and the params to supply to it // @@ -774,6 +774,13 @@ //not valid, so format the error message and stick it in the 'error' variable observable.error = ko.validation.formatMessage(ctx.message || rule.message, ctx.params); + //make a details object summary + observable.errorDetails = { + rule: rule, + params: ctx.params, + observable: observable, + message: observable.error + }; observable.__valid__(false); return false; } else { @@ -806,6 +813,13 @@ //not valid, so format the error message and stick it in the 'error' variable observable.error = ko.validation.formatMessage(msg || ctx.message || rule.message, ctx.params); + //make a details object summary + observable.errorDetails = { + rule: rule, + params: ctx.params, + observable: observable, + message: observable.error + }; observable.isValidating(false); observable.__valid__(isValid); }; @@ -842,6 +856,7 @@ } //finally if we got this far, make the observable valid again! observable.error = null; + observable.errorDetails = null; observable.__valid__(true); return true; }; diff --git a/Tests/validation-tests.js b/Tests/validation-tests.js index 03621c45..5f8afe11 100644 --- a/Tests/validation-tests.js +++ b/Tests/validation-tests.js @@ -1026,4 +1026,66 @@ asyncTest('Async Rule Is NOT Valid Test', function () { testObj.extend({ mustEqualAsync: 5 }); }); +//#endregion + +//#region error details + +module('error details'); + +test('errorDetails property is filled when not valid', function () { + var testObj = ko.observable('').extend({ required: true }); + + equal(testObj.isValid(), false); + equal(testObj.error, ko.validation.rules.required.message); + + ok(testObj.hasOwnProperty('errorDetails'), 'errorDetails property does not exist.'); + equal(testObj.errorDetails.rule, ko.validation.rules.required); + equal(testObj.errorDetails.params, true); + equal(testObj.errorDetails.observable, testObj); + equal(testObj.errorDetails.message, ko.validation.rules.required.message) +}); + +test('errorDetails property is null when valid', function () { + var testObj = ko.observable('').extend({ required: true }); + equal(testObj.isValid(), false); + + testObj('a value'); + + equal(testObj.isValid(), true); + equal(testObj.errorDetails.rule, null); +}); + +asyncTest('errorDetails property is filled when not valid async', function () { + + ko.validation.rules['mustEqualAsync'] = { + async: true, + validator: function (val, otherVal, callBack) { + var isValid = (val === otherVal); + setTimeout(function () { + callBack(isValid); + doAssertions(); + + start(); + }, 10); + }, + message: 'The field must equal {0}' + }; + ko.validation.registerExtenders(); //make sure the new rule is registered + + + var testObj = ko.observable(4); + + var doAssertions = function () { + ok(testObj.hasOwnProperty('errorDetails'), 'errorDetails property does not exist.'); + equal(testObj.errorDetails.rule, ko.validation.rules['mustEqualAsync']); + equal(testObj.errorDetails.params, 5); + equal(testObj.errorDetails.observable, testObj); + equal(testObj.errorDetails.message, 'The field must equal 5') + }; + + testObj.extend({ mustEqualAsync: 5 }); + + +}); + //#endregion \ No newline at end of file From 4bc55f3017b43642b7ba9867bd860a77af281148 Mon Sep 17 00:00:00 2001 From: delixfe Date: Thu, 28 Jun 2012 08:23:19 +0200 Subject: [PATCH 2/9] Added new option 'errorDetails' to grouping configuration. If errorDetails is truthy then errorDetails objects are returned instead of plain error messages. --- Src/knockout.validation.js | 9 +++++---- Tests/validation-tests.js | 25 ++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Src/knockout.validation.js b/Src/knockout.validation.js index dc8e8051..4c50f6e6 100644 --- a/Src/knockout.validation.js +++ b/Src/knockout.validation.js @@ -21,8 +21,9 @@ errorElementClass: 'validationElement', //class to decorate error element errorMessageClass: 'validationMessage', //class to decorate error message grouping: { - deep: false, //by default grouping is shallow - observable: true //and using observables + deep: false, //by default grouping is shallow + observable: true, //and using observables + errorDetails: false //insert plain error messages } }; @@ -207,7 +208,7 @@ var errors = []; ko.utils.arrayForEach(validatables(), function (observable) { if (!observable.isValid()) { - errors.push(observable.error); + errors.push(options.errorDetails ? observable.errorDetails : observable.error); } }); return errors; @@ -220,7 +221,7 @@ traverse(obj); // and traverse tree again ko.utils.arrayForEach(validatables(), function (observable) { if (!observable.isValid()) { - errors.push(observable.error); + errors.push(options.errorDetails ? observable.errorDetails : observable.error); } }); return errors; diff --git a/Tests/validation-tests.js b/Tests/validation-tests.js index 5f8afe11..6981dc74 100644 --- a/Tests/validation-tests.js +++ b/Tests/validation-tests.js @@ -1052,7 +1052,7 @@ test('errorDetails property is null when valid', function () { testObj('a value'); equal(testObj.isValid(), true); - equal(testObj.errorDetails.rule, null); + equal(testObj.errorDetails, null); }); asyncTest('errorDetails property is filled when not valid async', function () { @@ -1084,8 +1084,31 @@ asyncTest('errorDetails property is filled when not valid async', function () { }; testObj.extend({ mustEqualAsync: 5 }); +}); + +test('group with errorDetails options works - Not Observable', function () { + var vm = { + firstName: ko.observable().extend({ required: true }), + lastName: ko.observable().extend({ required: 2 }) + }; + var errors = ko.validation.group(vm, { errorDetails: true, observable: false }); + equals(errors().length, 2, 'Grouping correctly finds 2 invalid properties'); + equals(errors()[0], vm.firstName.errorDetails, 'group with errorDetails returns list of errorDetails'); + equals(errors()[1], vm.lastName.errorDetails, 'group with errorDetails returns list of errorDetails'); }); +test('group with errorDetails options works - Observable', function () { + var vm = { + firstName: ko.observable().extend({ required: true }), + lastName: ko.observable().extend({ required: 2 }) + }; + + var errors = ko.validation.group(vm, { errorDetails: true, observable: true }); + + equals(errors().length, 2, 'Grouping correctly finds 2 invalid properties'); + equals(errors()[0], vm.firstName.errorDetails, 'group with errorDetails returns list of errorDetails'); + equals(errors()[1], vm.lastName.errorDetails, 'group with errorDetails returns list of errorDetails'); +}); //#endregion \ No newline at end of file From 9b68bc2de1a06237da634287142df6206ff9577e Mon Sep 17 00:00:00 2001 From: delixfe Date: Fri, 23 Nov 2012 16:18:18 +0100 Subject: [PATCH 3/9] ErrorDetails have to be enabled explictly via option 'enableErrorDetails' --- Src/knockout.validation.js | 10 +++++++--- Tests/validation-tests.js | 11 ++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Src/knockout.validation.js b/Src/knockout.validation.js index 2d957c2e..d5f23f36 100644 --- a/Src/knockout.validation.js +++ b/Src/knockout.validation.js @@ -36,6 +36,7 @@ errorClass: null, // single class for error message and element errorElementClass: 'validationElement', // class to decorate error element errorMessageClass: 'validationMessage', // class to decorate error message + enableErrorDetails: false, // add a new property errorDetails which contains the rule, the params, the observable and the message grouping: { deep: false, //by default grouping is shallow observable: true, //and using observables @@ -237,7 +238,7 @@ var errors = []; ko.utils.arrayForEach(validatables(), function (observable) { if (!observable.isValid()) { - errors.push(options.errorDetails ? observable.errorDetails : observable.error); + errors.push(options.errorDetails && configuration.enableErrorDetails ? observable.errorDetails : observable.error); } }); return errors; @@ -250,7 +251,7 @@ traverse(obj); // and traverse tree again ko.utils.arrayForEach(validatables(), function (observable) { if (!observable.isValid()) { - errors.push(options.errorDetails ? observable.errorDetails : observable.error); + errors.push(options.errorDetails && configuration.enableErrorDetails ? observable.errorDetails : observable.error); } }); return errors; @@ -852,7 +853,9 @@ if (enable && !utils.isValidatable(observable)) { observable.error = null; // holds the error message, we only need one since we stop processing validators when one is invalid - observable.errorDetails = null; // + if(configuration.enableErrorDetails) { + observable.errorDetails = null; // holds detailed error informatino + } // observable.rules: // ObservableArray of Rule Contexts, where a Rule Context is simply the name of a rule and the params to supply to it // @@ -904,6 +907,7 @@ delete observable['isValidating']; delete observable['__valid__']; delete observable['isModified']; + if(configuration.enableErrorDetails) delete observable['errorDetails'] }; } else if (enable === false && utils.isValidatable(observable)) { diff --git a/Tests/validation-tests.js b/Tests/validation-tests.js index 36d6c152..d08b2658 100644 --- a/Tests/validation-tests.js +++ b/Tests/validation-tests.js @@ -1214,6 +1214,7 @@ asyncTest('Async Rule Is NOT Valid Test', function () { module('error details'); test('errorDetails property is filled when not valid', function () { + ko.validation.init({enableErrorDetails: true }, true); var testObj = ko.observable('').extend({ required: true }); equal(testObj.isValid(), false); @@ -1224,9 +1225,11 @@ test('errorDetails property is filled when not valid', function () { equal(testObj.errorDetails.params, true); equal(testObj.errorDetails.observable, testObj); equal(testObj.errorDetails.message, ko.validation.rules.required.message) + ko.validation.reset(); }); test('errorDetails property is null when valid', function () { + ko.validation.init({enableErrorDetails: true }, true); var testObj = ko.observable('').extend({ required: true }); equal(testObj.isValid(), false); @@ -1234,10 +1237,11 @@ test('errorDetails property is null when valid', function () { equal(testObj.isValid(), true); equal(testObj.errorDetails, null); + ko.validation.reset(); }); asyncTest('errorDetails property is filled when not valid async', function () { - + ko.validation.init({enableErrorDetails: true }, true); ko.validation.rules['mustEqualAsync'] = { async: true, validator: function (val, otherVal, callBack) { @@ -1265,9 +1269,11 @@ asyncTest('errorDetails property is filled when not valid async', function () { }; testObj.extend({ mustEqualAsync: 5 }); + ko.validation.init({enableErrorDetails: true }, true); }); test('group with errorDetails options works - Not Observable', function () { + ko.validation.init({enableErrorDetails: true }, true); var vm = { firstName: ko.observable().extend({ required: true }), lastName: ko.observable().extend({ required: 2 }) @@ -1278,9 +1284,11 @@ test('group with errorDetails options works - Not Observable', function () { equals(errors().length, 2, 'Grouping correctly finds 2 invalid properties'); equals(errors()[0], vm.firstName.errorDetails, 'group with errorDetails returns list of errorDetails'); equals(errors()[1], vm.lastName.errorDetails, 'group with errorDetails returns list of errorDetails'); + ko.validation.reset(); }); test('group with errorDetails options works - Observable', function () { + ko.validation.init({enableErrorDetails: true }, true); var vm = { firstName: ko.observable().extend({ required: true }), lastName: ko.observable().extend({ required: 2 }) @@ -1291,5 +1299,6 @@ test('group with errorDetails options works - Observable', function () { equals(errors().length, 2, 'Grouping correctly finds 2 invalid properties'); equals(errors()[0], vm.firstName.errorDetails, 'group with errorDetails returns list of errorDetails'); equals(errors()[1], vm.lastName.errorDetails, 'group with errorDetails returns list of errorDetails'); + ko.validation.reset(); }); //#endregion From c00d1e59d607db95dc97055e1e897bec5d00ac9b Mon Sep 17 00:00:00 2001 From: delixfe Date: Fri, 23 Nov 2012 16:45:58 +0100 Subject: [PATCH 4/9] enableErrorDetails was not checked correctly. --- Src/knockout.validation.js | 38 +++++++++++++++++++------------------- Tests/validation-tests.js | 11 +++++++++++ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/Src/knockout.validation.js b/Src/knockout.validation.js index d5f23f36..ad6db224 100644 --- a/Src/knockout.validation.js +++ b/Src/knockout.validation.js @@ -923,16 +923,17 @@ if (!rule.validator(observable(), ctx.params === undefined ? true : ctx.params)) { // default param is true, eg. required = true //not valid, so format the error message and stick it in the 'error' variable - observable.error = ko.validation.formatMessage(ctx.message || rule.message, ctx.params); - //make a details object summary - observable.errorDetails = { - rule: rule, - params: ctx.params, - observable: observable, - message: observable.error - }; observable.error = exports.formatMessage(ctx.message || rule.message, ctx.params); observable.__valid__(false); + if(configuration.enableErrorDetails) { + //make a details object summary + observable.errorDetails = { + rule: rule, + params: ctx.params, + observable: observable, + message: observable.error + }; + } return false; } else { return true; @@ -966,18 +967,17 @@ //not valid, so format the error message and stick it in the 'error' variable observable.error = exports.formatMessage(msg || ctx.message || rule.message, ctx.params); observable.__valid__(isValid); + if(configuration.enableErrorDetails) { + //make a details object summary + observable.errorDetails = { + rule: rule, + params: ctx.params, + observable: observable, + message: observable.error + }; + } } - //not valid, so format the error message and stick it in the 'error' variable - observable.error = ko.validation.formatMessage(msg || ctx.message || rule.message, ctx.params); - //make a details object summary - observable.errorDetails = { - rule: rule, - params: ctx.params, - observable: observable, - message: observable.error - }; - // tell it that we're done observable.isValidating(false); }; @@ -1018,7 +1018,7 @@ } //finally if we got this far, make the observable valid again! observable.error = null; - observable.errorDetails = null; + if(configuration.enableErrorDetails) observable.errorDetails = null; observable.__valid__(true); return true; }; diff --git a/Tests/validation-tests.js b/Tests/validation-tests.js index d08b2658..3a8dd5b0 100644 --- a/Tests/validation-tests.js +++ b/Tests/validation-tests.js @@ -1301,4 +1301,15 @@ test('group with errorDetails options works - Observable', function () { equals(errors()[1], vm.lastName.errorDetails, 'group with errorDetails returns list of errorDetails'); ko.validation.reset(); }); + +test('errorDetails property is not defined if enableErrorDetails equals false', function () { + // enableErrorDetails is disabled by default + //ko.validation.init({enableErrorDetails: false }, true); + var testObj = ko.observable('').extend({ required: true }); + + equal(testObj.isValid(), false); + equal(testObj.error, ko.validation.rules.required.message); + + ok(!testObj.hasOwnProperty('errorDetails'), 'errorDetails property does exist.'); +}); //#endregion From e643e666c89531a0cfaca8befbeea6e8f547dec7 Mon Sep 17 00:00:00 2001 From: delixfe Date: Mon, 26 Nov 2012 08:06:09 +0100 Subject: [PATCH 5/9] Changed the order in validateSync and validateAsync because otherwise the call to observable.__valid__(isValid) triggers the reevaluation of computeds before errorDetails is written. --- Src/knockout.validation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Src/knockout.validation.js b/Src/knockout.validation.js index ad6db224..566faf53 100644 --- a/Src/knockout.validation.js +++ b/Src/knockout.validation.js @@ -924,7 +924,6 @@ //not valid, so format the error message and stick it in the 'error' variable observable.error = exports.formatMessage(ctx.message || rule.message, ctx.params); - observable.__valid__(false); if(configuration.enableErrorDetails) { //make a details object summary observable.errorDetails = { @@ -934,6 +933,7 @@ message: observable.error }; } + observable.__valid__(false); return false; } else { return true; @@ -966,7 +966,6 @@ if (!isValid) { //not valid, so format the error message and stick it in the 'error' variable observable.error = exports.formatMessage(msg || ctx.message || rule.message, ctx.params); - observable.__valid__(isValid); if(configuration.enableErrorDetails) { //make a details object summary observable.errorDetails = { @@ -976,6 +975,7 @@ message: observable.error }; } + observable.__valid__(isValid); } // tell it that we're done From 7bd7a109833a65fad0b0bcd8d29f75fa324ac6c1 Mon Sep 17 00:00:00 2001 From: delixfe Date: Mon, 26 Nov 2012 08:42:33 +0100 Subject: [PATCH 6/9] Added missing semicolon. --- Src/knockout.validation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/knockout.validation.js b/Src/knockout.validation.js index 566faf53..03881c05 100644 --- a/Src/knockout.validation.js +++ b/Src/knockout.validation.js @@ -907,7 +907,7 @@ delete observable['isValidating']; delete observable['__valid__']; delete observable['isModified']; - if(configuration.enableErrorDetails) delete observable['errorDetails'] + if(configuration.enableErrorDetails) delete observable['errorDetails']; }; } else if (enable === false && utils.isValidatable(observable)) { From 3ad368fb2bc1c2e52ab267468b6cd1da03ae33da Mon Sep 17 00:00:00 2001 From: delixfe Date: Mon, 3 Dec 2012 14:07:43 +0100 Subject: [PATCH 7/9] Fixed typo in comment. --- Src/knockout.validation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/knockout.validation.js b/Src/knockout.validation.js index 6c35ef6f..e97bcc22 100644 --- a/Src/knockout.validation.js +++ b/Src/knockout.validation.js @@ -880,7 +880,7 @@ observable.error = null; // holds the error message, we only need one since we stop processing validators when one is invalid if(configuration.enableErrorDetails) { - observable.errorDetails = null; // holds detailed error informatino + observable.errorDetails = null; // holds detailed error information } // observable.rules: // ObservableArray of Rule Contexts, where a Rule Context is simply the name of a rule and the params to supply to it From f763c0c13a1a8993e60e6e441d965b38d6e22ae1 Mon Sep 17 00:00:00 2001 From: delixfe Date: Mon, 3 Dec 2012 16:10:02 +0100 Subject: [PATCH 8/9] Properties of errorDetails are observable (except for observable). To solve the problem of going from one invalid state to the next not updating lists bound to errorDetails. --- Src/knockout.validation.js | 36 ++++++++++++++++++++---------------- Tests/validation-tests.js | 32 ++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/Src/knockout.validation.js b/Src/knockout.validation.js index e97bcc22..c9f6463a 100644 --- a/Src/knockout.validation.js +++ b/Src/knockout.validation.js @@ -880,7 +880,14 @@ observable.error = null; // holds the error message, we only need one since we stop processing validators when one is invalid if(configuration.enableErrorDetails) { - observable.errorDetails = null; // holds detailed error information + // holds detailed error information + observable.errorDetails = { + rule: ko.observable(null), + params: ko.observable(null), + observable: observable, + message: ko.observable(null) + }; + } // observable.rules: // ObservableArray of Rule Contexts, where a Rule Context is simply the name of a rule and the params to supply to it @@ -926,6 +933,7 @@ observable.__valid__._subscriptions['change'] = []; h_change.dispose(); h_obsValidationTrigger.dispose(); + // TODO: dispose errorDetails' properties delete observable['rules']; delete observable['error']; @@ -951,13 +959,9 @@ //not valid, so format the error message and stick it in the 'error' variable observable.error = exports.formatMessage(ctx.message || rule.message, ctx.params); if(configuration.enableErrorDetails) { - //make a details object summary - observable.errorDetails = { - rule: rule, - params: ctx.params, - observable: observable, - message: observable.error - }; + observable.errorDetails.rule(rule); + observable.errorDetails.params(ctx.params); + observable.errorDetails.message(observable.error); } observable.__valid__(false); return false; @@ -993,13 +997,9 @@ //not valid, so format the error message and stick it in the 'error' variable observable.error = exports.formatMessage(msg || ctx.message || rule.message, ctx.params); if(configuration.enableErrorDetails) { - //make a details object summary - observable.errorDetails = { - rule: rule, - params: ctx.params, - observable: observable, - message: observable.error - }; + observable.errorDetails.rule(rule); + observable.errorDetails.params(ctx.params); + observable.errorDetails.message(observable.error); } observable.__valid__(isValid); } @@ -1044,7 +1044,11 @@ } //finally if we got this far, make the observable valid again! observable.error = null; - if(configuration.enableErrorDetails) observable.errorDetails = null; + if(configuration.enableErrorDetails) { + observable.errorDetails.rule(null); + observable.errorDetails.params(null); + observable.errorDetails.message(null); + } observable.__valid__(true); return true; }; diff --git a/Tests/validation-tests.js b/Tests/validation-tests.js index c6cdc36d..1c67c95d 100644 --- a/Tests/validation-tests.js +++ b/Tests/validation-tests.js @@ -1271,14 +1271,14 @@ test('errorDetails property is filled when not valid', function () { equal(testObj.error, ko.validation.rules.required.message); ok(testObj.hasOwnProperty('errorDetails'), 'errorDetails property does not exist.'); - equal(testObj.errorDetails.rule, ko.validation.rules.required); - equal(testObj.errorDetails.params, true); + equal(testObj.errorDetails.rule(), ko.validation.rules.required); + equal(testObj.errorDetails.params(), true); equal(testObj.errorDetails.observable, testObj); - equal(testObj.errorDetails.message, ko.validation.rules.required.message) + equal(testObj.errorDetails.message(), ko.validation.rules.required.message) ko.validation.reset(); }); -test('errorDetails property is null when valid', function () { +test('errorDetails properties are null when valid', function () { ko.validation.init({enableErrorDetails: true }, true); var testObj = ko.observable('').extend({ required: true }); equal(testObj.isValid(), false); @@ -1286,7 +1286,9 @@ test('errorDetails property is null when valid', function () { testObj('a value'); equal(testObj.isValid(), true); - equal(testObj.errorDetails, null); + equal(testObj.errorDetails.rule(), null); + equal(testObj.errorDetails.params(), null); + equal(testObj.errorDetails.message(), null); ko.validation.reset(); }); @@ -1312,10 +1314,10 @@ asyncTest('errorDetails property is filled when not valid async', function () { var doAssertions = function () { ok(testObj.hasOwnProperty('errorDetails'), 'errorDetails property does not exist.'); - equal(testObj.errorDetails.rule, ko.validation.rules['mustEqualAsync']); - equal(testObj.errorDetails.params, 5); + equal(testObj.errorDetails.rule(), ko.validation.rules['mustEqualAsync']); + equal(testObj.errorDetails.params(), 5); equal(testObj.errorDetails.observable, testObj); - equal(testObj.errorDetails.message, 'The field must equal 5') + equal(testObj.errorDetails.message(), 'The field must equal 5') }; testObj.extend({ mustEqualAsync: 5 }); @@ -1362,4 +1364,18 @@ test('errorDetails property is not defined if enableErrorDetails equals false', ok(!testObj.hasOwnProperty('errorDetails'), 'errorDetails property does exist.'); }); + +test('going from one invalid state to the next creates the correct errorDetails (required -> maxLength)', function () { + ko.validation.init( { enableErrorDetails: true }, true); + var vm = { item : ko.observable().extend( { maxLength: 2, required: true } ) }; + var errors = ko.validation.group(vm, { deep: true, observable: true, errorDetails: true }); + + equals(errors().length, 1, "has initially one error"); + equals(errors()[0].rule().message, ko.validation.rules.required.message); + + // insert too long text triggering maxLength rule + vm.item('12345'); + equals(errors()[0].rule().message, "Please enter no more than {0} characters."); + ko.validation.reset(); +}); //#endregion From e8cf78f7e749e0afd18929352caaef74889cfec2 Mon Sep 17 00:00:00 2001 From: delixfe Date: Mon, 3 Dec 2012 16:24:25 +0100 Subject: [PATCH 9/9] Dispose errorDetails properties. --- Src/knockout.validation.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Src/knockout.validation.js b/Src/knockout.validation.js index c9f6463a..853676a6 100644 --- a/Src/knockout.validation.js +++ b/Src/knockout.validation.js @@ -933,7 +933,11 @@ observable.__valid__._subscriptions['change'] = []; h_change.dispose(); h_obsValidationTrigger.dispose(); - // TODO: dispose errorDetails' properties + if(configuration.enableErrorDetails) { + observable.errorDetails.rule.dispose(); + observable.errorDetails.params.dispose(); + observable.errorDetails.message.dispose(); + } delete observable['rules']; delete observable['error'];