diff --git a/spec/validation-element-spec.js b/spec/validation-element-spec.js index 05b741d..a11d2c9 100644 --- a/spec/validation-element-spec.js +++ b/spec/validation-element-spec.js @@ -100,5 +100,16 @@ describe('Validation message element', function () { expect(messageElement).toHaveClass('validation-message'); expect(messageElement).toHaveClass('validation-fixed'); }); + + it('does not throw an error when the element is removed from the dom and the validation is triggered', function () { + function removeValidationMessageElementAndValidate() { + $('#messageElement').remove(); + + $('#firstName').val('').trigger('change'); + $('#firstName').val('Chuck').trigger('change'); + } + + expect(removeValidationMessageElementAndValidate).not.toThrow(); + }); }); }); diff --git a/src/ko-validation.js b/src/ko-validation.js index c7d7209..58a54d2 100644 --- a/src/ko-validation.js +++ b/src/ko-validation.js @@ -140,11 +140,13 @@ ko.validation.registerValidator = function (name, validatorFactory) { }; }); ko.bindingHandlers.text.update(element, observable.validationMessage); - ko.bindingHandlers.css.update(element.parentNode, function () { - return { - 'error': observable.validationState() === ko.validation.validationStates.INVALID - }; - }); + if (element.parentNode) { + ko.bindingHandlers.css.update(element.parentNode, function () { + return { + 'error': observable.validationState() === ko.validation.validationStates.INVALID + }; + }); + } } function initValidationFor(inputElement, observable) { @@ -184,8 +186,9 @@ ko.validation.registerValidator = function (name, validatorFactory) { ko.bindingHandlers.validationMessage = { init: function (element, valueAccessor) { - var observable = valueAccessor(); + var observable, subscription; + observable = valueAccessor(); if (!ko.validation.utils.hasValidators(observable)) { throw new Error("'validationMessage' should be used with an observable that has validation"); } @@ -194,9 +197,12 @@ ko.validation.registerValidator = function (name, validatorFactory) { ko.bindingHandlers.css.update(element, function () { return { 'validation-message': true }; }); - observable.validationState.subscribe(function () { + subscription = observable.validationState.subscribe(function () { updateValidationMessage(element, observable); }); + ko.utils.domNodeDisposal.addDisposeCallback(element, function () { + subscription.dispose(); + }); } };