From dafaff0a0205bec61c0389f3c2868b880995dcc4 Mon Sep 17 00:00:00 2001 From: Nikolay Poryadin Date: Wed, 20 Mar 2019 20:09:34 +0300 Subject: [PATCH] Fixes #16158: Fix multiple select validation was trigged on other fields blur event --- framework/CHANGELOG.md | 1 + framework/assets/yii.activeForm.js | 74 +++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 465a81d288..a1cb2db813 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,6 +4,7 @@ Yii Framework 2 Change Log 2.0.17 under development ------------------------ +- Bug #16158: Fix multiple select validation was trigged on other fields blur event (GHopperMSK) - Bug #16335: Fixed in `yii\filters\AccessRule::matchIP()` user IP validation with netmask in rule (omentes) - Bug #9438, #13740, #15037: Handle DB session callback custom fields before session closed (lubosdz) - Bug #16681: `ActiveField::inputOptions` were not used during some widgets rendering (GHopperMSK) diff --git a/framework/assets/yii.activeForm.js b/framework/assets/yii.activeForm.js index 1d524cc6ee..b86c24c0ff 100644 --- a/framework/assets/yii.activeForm.js +++ b/framework/assets/yii.activeForm.js @@ -539,7 +539,7 @@ attribute.status = 2; } $.each(data.attributes, function () { - if (this.value !== getValue($form, this)) { + if (!isEqual(this.value, getValue($form, this))) { this.status = 2; forceValidate = true; } @@ -565,6 +565,78 @@ }, validationDelay ? validationDelay : 200); }; + /** + * Compares two value whatever it objects, arrays or simple types + * @param val1 + * @param val2 + * @returns boolean + */ + var isEqual = function(val1, val2) { + // objects + if (val1 instanceof Object) { + return isObjectsEqual(val1, val2) + } + + // arrays + if (Array.isArray(val1)) { + return isArraysEqual(val1, val2); + } + + // simple types + return val1 === val2; + }; + + /** + * Compares two objects + * @param obj1 + * @param obj2 + * @returns boolean + */ + var isObjectsEqual = function(obj1, obj2) { + if (!(obj1 instanceof Object) || !(obj2 instanceof Object)) { + return false; + } + + var keys1 = Object.keys(obj1); + var keys2 = Object.keys(obj2); + if (keys1.length !== keys2.length) { + return false; + } + + for (var i = 0; i < keys1.length; i += 1) { + if (!obj2.hasOwnProperty(keys1[i])) { + return false; + } + if (obj1[keys1[i]] !== obj2[keys1[i]]) { + return false; + } + } + + return true; + }; + + /** + * Compares two arrays + * @param arr1 + * @param arr2 + * @returns boolean + */ + var isArraysEqual = function(arr1, arr2) { + if (!Array.isArray(arr1) || !Array.isArray(arr2)) { + return false; + } + + if (arr1.length !== arr2.length) { + return false; + } + for (var i = 0; i < arr1.length; i += 1) { + if (arr1[i] !== arr2[i]) { + return false; + } + } + return true; + }; + /** * Returns an array prototype with a shortcut method for adding a new deferred. * The context of the callback will be the deferred object so it can be resolved like ```this.resolve()```