diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 55f26fc717..4594690f1a 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -21,6 +21,7 @@ Yii Framework 2 Change Log - Bug #17299: Fixed adding of input error class in `\yii\widgets\ActiveField::widget` (alexkart) - Bug #17328: Added mime aliases for BMP and SVG files (cmoeke) - Bug #17336: Fixed wildcard matching in Event::hasHandlers() (samdark) +- Bug #12080: Fixed afterValidate triggering when any validation occurs (czzplnm) 2.0.19 May 21, 2019 diff --git a/framework/assets/yii.activeForm.js b/framework/assets/yii.activeForm.js index 3b416c0469..e4c3962e8d 100644 --- a/framework/assets/yii.activeForm.js +++ b/framework/assets/yii.activeForm.js @@ -459,9 +459,9 @@ $errorElement = data.settings.validationStateOn === 'input' ? $input : $container; $errorElement.removeClass( - data.settings.validatingCssClass + ' ' + - data.settings.errorCssClass + ' ' + - data.settings.successCssClass + data.settings.validatingCssClass + ' ' + + data.settings.errorCssClass + ' ' + + data.settings.successCssClass ); $container.find(this.error).html(''); }); @@ -705,19 +705,20 @@ return false; } + var errorAttributes = []; + var $input = findInput($form, this); + $.each(data.attributes, function () { + var hasError = (submitting && updateInput($form, this, messages)) || (!submitting && attrHasError($form, this, messages)); + + if (!$input.is(":disabled") && !this.cancelled && hasError) { + errorAttributes.push(this); + } + }); + + $form.trigger(events.afterValidate, [messages, errorAttributes]); + if (submitting) { - var errorAttributes = [], $input; - $.each(data.attributes, function () { - $input = findInput($form, this); - if (!$input.is(":disabled") && !this.cancelled && updateInput($form, this, messages)) { - errorAttributes.push(this); - } - }); - - $form.trigger(events.afterValidate, [messages, errorAttributes]); - updateSummary($form, messages); - if (errorAttributes.length) { if (data.settings.scrollToError) { var top = $form.find($.map(errorAttributes, function(attribute) { @@ -787,7 +788,7 @@ var updateInput = function ($form, attribute, messages) { var data = $form.data('yiiActiveForm'), $input = findInput($form, attribute), - hasError = false; + hasError = attrHasError($form, attribute, messages); if (!$.isArray(messages[attribute.id])) { messages[attribute.id] = []; @@ -795,7 +796,6 @@ attribute.status = 1; if ($input.length) { - hasError = messages[attribute.id].length > 0; var $container = $form.find(attribute.container); var $error = $container.find(attribute.error); updateAriaInvalid($form, attribute, hasError); @@ -809,11 +809,11 @@ $error.html(messages[attribute.id][0]); } $errorElement.removeClass(data.settings.validatingCssClass + ' ' + data.settings.successCssClass) - .addClass(data.settings.errorCssClass); + .addClass(data.settings.errorCssClass); } else { $error.empty(); $errorElement.removeClass(data.settings.validatingCssClass + ' ' + data.settings.errorCssClass + ' ') - .addClass(data.settings.successCssClass); + .addClass(data.settings.successCssClass); } attribute.value = getValue($form, attribute); } @@ -823,6 +823,28 @@ return hasError; }; + /** + * Checks if a particular attribute has an error + * @param $form the form jQuery object + * @param attribute object the configuration for a particular attribute. + * @param messages array the validation error messages + * @return boolean whether there is a validation error for the specified attribute + */ + var attrHasError = function ($form, attribute, messages) { + var $input = findInput($form, attribute), + hasError = false; + + if (!$.isArray(messages[attribute.id])) { + messages[attribute.id] = []; + } + + if ($input.length) { + hasError = messages[attribute.id].length > 0; + } + + return hasError; + }; + /** * Updates the error summary. * @param $form the form jQuery object diff --git a/tests/js/tests/yii.activeForm.test.js b/tests/js/tests/yii.activeForm.test.js index 23733a5366..323b74ab1f 100644 --- a/tests/js/tests/yii.activeForm.test.js +++ b/tests/js/tests/yii.activeForm.test.js @@ -78,7 +78,7 @@ describe('yii.activeForm', function () { assert.isTrue(afterValidateSpy.calledOnce); }); }); - + describe('with disabled fields', function () { var inputTypes = { test_radio: 'radioList', @@ -184,5 +184,38 @@ describe('yii.activeForm', function () { assert.equal('New value', eventData.value); }); }); + + describe('afterValidate', function () { + var afterValidateSpy; + var eventData = null; + + before(function () { + afterValidateSpy = sinon.spy(function (event, data) { + eventData = data; + }); + }); + + after(function () { + afterValidateSpy.reset(); + }); + + // https://github.com/yiisoft/yii2/issues/12080 + + it('afterValidate should trigger when not submitting', function () { + var inputId = 'name', + $input = $('#' + inputId); + + $activeForm = $('#w0'); + $activeForm.yiiActiveForm( + [{ + "id": inputId, + "name": "name", + input: '#' + inputId + }], []).on('afterValidate', afterValidateSpy); + + $activeForm.yiiActiveForm('validate'); + assert.notEqual(null, eventData); + }); + }); }); });