From 41d232f25e76c0b87492e8ffa7645c1c83824f35 Mon Sep 17 00:00:00 2001 From: PowerGamer1 Date: Wed, 28 Dec 2022 17:35:42 +0200 Subject: [PATCH] Bug #18867: Fixed multiple issues with `yii\grid\CheckboxColumn` - "check all" checkbox not being checked on page load when all data row checkboxes are initially checked - clicking checkboxes triggered "change" event for other checkboxes that do not change their state - "check all" checkbox not being checked when disabled checkboxes are present and clicking last non-checked data row checkbox --- framework/CHANGELOG.md | 1 + framework/assets/yii.gridView.js | 17 +++++++++-------- tests/js/tests/yii.gridView.test.js | 16 ++++++++-------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 65e172da84..4d2c206976 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -3,6 +3,7 @@ Yii Framework 2 Change Log 2.0.48 under development ------------------------ +- Bug #18867: Fixed multiple issues with `yii\grid\CheckboxColumn`: "check all" checkbox not being checked on page load when all data row checkboxes are initially checked; clicking checkboxes triggered "change" event for other checkboxes that do not change their state; "check all" checkbox not being checked when disabled checkboxes are present and clicking last non-checked data row checkbox (PowerGamer1) - Bug #19635: PHP 8.2 compatibility fix for `yii\validators\DateValidator` (PowerGamer1) - Bug #17194: Fix unnecessary SQL updates in the database on attributes typecast via `yii\behaviors\AttributeTypecastBehavior` (aivchen) - Bug #19693: Fix db/Command not caching `NULL` result with scalar fetchMode (Arkeins) diff --git a/framework/assets/yii.gridView.js b/framework/assets/yii.gridView.js index 825ff5044d..dc7536df30 100644 --- a/framework/assets/yii.gridView.js +++ b/framework/assets/yii.gridView.js @@ -188,16 +188,17 @@ if (!options.multiple || !options.checkAll) { return; } - var checkAll = "#" + id + " input[name='" + options.checkAll + "']"; - var inputs = options['class'] ? "input." + options['class'] : "input[name='" + options.name + "']"; - var inputsEnabled = "#" + id + " " + inputs + ":enabled"; - initEventHandler($grid, 'checkAllRows', 'click.yiiGridView', checkAll, function () { - $grid.find(inputs + ":enabled").prop('checked', this.checked).change(); + var checkAllInput = "input[name='" + options.checkAll + "']"; + var inputs = (options['class'] ? "input." + options['class'] : "input[name='" + options.name + "']") + ":enabled"; + initEventHandler($grid, 'checkAllRows', 'click.yiiGridView', "#" + id + " " + checkAllInput, function () { + $grid.find(inputs + (this.checked ? ":not(:checked)" : ":checked")).prop('checked', this.checked).change(); }); - initEventHandler($grid, 'checkRow', 'click.yiiGridView', inputsEnabled, function () { + var handler = function () { var all = $grid.find(inputs).length == $grid.find(inputs + ":checked").length; - $grid.find("input[name='" + options.checkAll + "']").prop('checked', all).change(); - }); + $grid.find(checkAllInput + (all ? ":not(:checked)" : ":checked")).prop('checked', all).change(); + }; + initEventHandler($grid, 'checkRow', 'click.yiiGridView', "#" + id + " " + inputs, handler); + handler(); // Ensure "check all" checkbox is checked on page load if all data row checkboxes are initially checked. }, getSelectedRows: function () { diff --git a/tests/js/tests/yii.gridView.test.js b/tests/js/tests/yii.gridView.test.js index bc1feb6cee..85f5b56637 100644 --- a/tests/js/tests/yii.gridView.test.js +++ b/tests/js/tests/yii.gridView.test.js @@ -658,8 +658,8 @@ describe('yii.gridView', function () { click($checkAllCheckbox); assert.lengthOf($checkRowCheckboxes.filter(':checked'), 3); assert.isTrue($checkAllCheckbox.prop('checked')); - // "change" should be called 3 times, 1 time per each row, no matter what state it has - assert.equal(changedSpy.callCount, 3); + // "change" should be called 2 more times for the remaining 2 unchecked rows + assert.equal(changedSpy.callCount, 2); // Uncheck first row changedSpy.reset(); @@ -711,12 +711,12 @@ describe('yii.gridView', function () { checkAll: 'selection_all' }); - // Check first row ("prop" should be called once) + // Click first row checkbox ("prop" on "check all" checkbox should not be called) click($gridView.find('input[name="selection[]"][value="1"]')); - // Check all rows ("prop" should be called 2 times, 1 time for each row) + // Click "check all" checkbox ("prop" should be called once on the remaining unchecked row) click($gridView.find('input[name="selection_all"]')); - assert.equal(jQueryPropStub.callCount, 3); + assert.equal(jQueryPropStub.callCount, 1); }); }); }); @@ -831,9 +831,9 @@ describe('yii.gridView', function () { click($gridView2.find('input[name="selection[]"][value="1"]')); assert.equal(jQueryPropStub.callCount, 0); - click($checkRowCheckboxes.filter('[value="1"]')); // Check first row ("prop" should be called once) - click($checkAllCheckbox); // Check all rows ("prop" should be called 3 times, 1 time for each row) - assert.equal(jQueryPropStub.callCount, 4); + click($checkRowCheckboxes.filter('[value="1"]')); // Click first row checkbox ("prop" on "check all" checkbox should not be called) + click($checkAllCheckbox); // Click "check all" checkbox ("prop" should be called 2 times on the remaining unchecked rows) + assert.equal(jQueryPropStub.callCount, 2); }); });