mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-10-31 10:39:59 +08:00 
			
		
		
		
	Merge pull request #19909 from tim-fischer-maschinensucher/13920-validation-marks-valid-field-as-invalid
Fix #13920: Fixed erroneous validation for specific cases
This commit is contained in:
		| @ -4,6 +4,7 @@ Yii Framework 2 Change Log | ||||
| 2.0.50 under development | ||||
| ------------------------ | ||||
|  | ||||
| - Bug #13920: Fixed erroneous validation for specific cases (tim-fischer-maschinensucher) | ||||
| - Bug #19927: Fixed `console\controllers\MessageController` when saving translations to database: fixed FK error when adding new string and language at the same time, checking/regenerating all missing messages and dropping messages for unused languages (atrandafir) | ||||
| - Enh #12743: Added new methods `BaseActiveRecord::loadRelations()` and `BaseActiveRecord::loadRelationsFor()` to eager load related models for existing primary model instances (PowerGamer1) | ||||
|  | ||||
|  | ||||
| @ -395,9 +395,11 @@ | ||||
|                         data: $form.serialize() + extData, | ||||
|                         dataType: data.settings.ajaxDataType, | ||||
|                         complete: function (jqXHR, textStatus) { | ||||
|                             currentAjaxRequest = null; | ||||
|                             $form.trigger(events.ajaxComplete, [jqXHR, textStatus]); | ||||
|                         }, | ||||
|                         beforeSend: function (jqXHR, settings) { | ||||
|                             currentAjaxRequest = jqXHR; | ||||
|                             $form.trigger(events.ajaxBeforeSend, [jqXHR, settings]); | ||||
|                         }, | ||||
|                         success: function (msgs) { | ||||
| @ -563,6 +565,9 @@ | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (currentAjaxRequest !== null) { | ||||
|             currentAjaxRequest.abort(); | ||||
|         } | ||||
|         if (data.settings.timer !== undefined) { | ||||
|             clearTimeout(data.settings.timer); | ||||
|         } | ||||
| @ -929,4 +934,7 @@ | ||||
|             $form.find(attribute.input).attr('aria-invalid', hasError ? 'true' : 'false'); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     var currentAjaxRequest = null; | ||||
|  | ||||
| })(window.jQuery); | ||||
|  | ||||
| @ -48,3 +48,15 @@ | ||||
|         <div class="help-block"></div> | ||||
|     </div> | ||||
| </form> | ||||
| <form id="w3"> | ||||
|     <div class="form-group field-test-text2 required"> | ||||
|         <label class="control-label" for="test-text2">Test text</label> | ||||
|         <input type="text" id="test-text2" class="form-control" name="Test[text2]" aria-required="true"> | ||||
|         <div class="help-block"></div> | ||||
|     </div> | ||||
|     <div class="form-group field-test-text3 required"> | ||||
|         <label class="control-label" for="test-text3">Test text</label> | ||||
|         <input type="text" id="test-text3" class="form-control" name="Test[text3]" aria-required="true"> | ||||
|         <div class="help-block"></div> | ||||
|     </div> | ||||
| </form> | ||||
|  | ||||
| @ -27,6 +27,21 @@ describe('yii.activeForm', function () { | ||||
|         var script = new vm.Script(code); | ||||
|         var context = new vm.createContext({window: window, document: window.document, yii: yii}); | ||||
|         script.runInContext(context); | ||||
|         /** This is a workaround for a jsdom issue, that prevents :hidden and :visible from working as expected. | ||||
|          * @see https://github.com/jsdom/jsdom/issues/1048 */ | ||||
|         context.window.Element.prototype.getClientRects = function () { | ||||
|             var node = this; | ||||
|             while(node) { | ||||
|                 if(node === document) { | ||||
|                     break; | ||||
|                 } | ||||
|                 if (!node.style || node.style.display === 'none' || node.style.visibility === 'hidden') { | ||||
|                     return []; | ||||
|                 } | ||||
|                 node = node.parentNode; | ||||
|             } | ||||
|             return [{width: 100, height: 100}]; | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     var activeFormHtml = fs.readFileSync('tests/js/data/yii.activeForm.html', 'utf-8'); | ||||
| @ -117,6 +132,60 @@ describe('yii.activeForm', function () { | ||||
|                 assert.isFalse($activeForm.data('yiiActiveForm').validated); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('with ajax validation', function () { | ||||
|             describe('with rapid validation of multiple fields', function () { | ||||
|                 it('should cancel overlapping ajax requests and not display outdated validation results', function () { | ||||
|                     $activeForm = $('#w3'); | ||||
|                     $activeForm.yiiActiveForm([{ | ||||
|                         id: 'test-text2', | ||||
|                         input: '#test-text2', | ||||
|                         container: '.field-test-text2', | ||||
|                         enableAjaxValidation: true | ||||
|                     }, { | ||||
|                         id: 'test-text3', | ||||
|                         input: '#test-text3', | ||||
|                         container: '.field-test-text3', | ||||
|                         enableAjaxValidation: true | ||||
|                     }], { | ||||
|                         validationUrl: '' | ||||
|                     }); | ||||
|  | ||||
|                     let requests = []; | ||||
|                     function fakeAjax(object) { | ||||
|                         const request = { | ||||
|                             jqXHR: { | ||||
|                                 abort: function () { | ||||
|                                     request.aborted = true; | ||||
|                                 } | ||||
|                             }, | ||||
|                             aborted: false, | ||||
|                             respond: function (response) { | ||||
|                                 if (this.aborted) { | ||||
|                                     return; | ||||
|                                 } | ||||
|                                 object.success(response); | ||||
|                                 object.complete(this.jqXHR, ''); | ||||
|                             } | ||||
|                         }; | ||||
|                         requests.push(request); | ||||
|                         object.beforeSend(request.jqXHR, ''); | ||||
|                     } | ||||
|  | ||||
|                     const ajaxStub = sinon.stub($, 'ajax', fakeAjax); | ||||
|                     $activeForm.yiiActiveForm('validateAttribute', 'test-text2'); | ||||
|                     assert.isTrue(requests.length === 1); | ||||
|                     $activeForm.yiiActiveForm('validateAttribute', 'test-text3'); | ||||
|                     // When validateAttribute was called on text2, its value was valid. | ||||
|                     // The value of text3 wasn't. | ||||
|                     requests[0].respond({'test-text3': ['Field cannot be empty']}); | ||||
|                     // When validateAttribute was called on text3, its value was valid. | ||||
|                     requests[1].respond([]); | ||||
|                     assert.isTrue($activeForm.find('.field-test-text3').hasClass('has-success')); | ||||
|                     ajaxStub.restore(); | ||||
|                 }); | ||||
|             }); | ||||
|         }) | ||||
|     }); | ||||
|  | ||||
|     describe('resetForm method', function () { | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Bizley
					Bizley