From bf2b9fa2fca4407ab3b025613bcb27b19114e1d9 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Mon, 25 May 2020 10:57:51 -0300 Subject: [PATCH 1/3] fix(b-form-checkbox-group, b-form-radio-group): only emit `input` when value loosely changes --- src/mixins/form-radio-check-group.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mixins/form-radio-check-group.js b/src/mixins/form-radio-check-group.js index 3c7991bebee..9a6e712a515 100644 --- a/src/mixins/form-radio-check-group.js +++ b/src/mixins/form-radio-check-group.js @@ -1,4 +1,5 @@ import { htmlOrText } from '../utils/html' +import looseEqual from '../utils/loose-equal' import normalizeSlotMixin from './normalize-slot' import { BFormCheckbox } from '../components/form-checkbox/form-checkbox' import { BFormRadio } from '../components/form-radio/form-radio' @@ -70,8 +71,10 @@ export default { checked(newVal) { this.localChecked = newVal }, - localChecked(newVal) { - this.$emit('input', newVal) + localChecked(newVal, oldVal) { + if (!looseEqual(newVal, oldVal)) { + this.$emit('input', newVal) + } } }, render(h) { From 156ba3b54692f29958c84e7ab3c159d13b257ded Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Mon, 25 May 2020 11:32:33 -0300 Subject: [PATCH 2/3] Update loose-equal.js --- src/utils/loose-equal.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/utils/loose-equal.js b/src/utils/loose-equal.js index d53c4bfefb2..698a511d2f7 100644 --- a/src/utils/loose-equal.js +++ b/src/utils/loose-equal.js @@ -1,4 +1,4 @@ -import { keys } from './object' +import { hasOwnProperty, keys } from './object' import { isArray, isDate, isObject } from './inspect' // Assumes both a and b are arrays! @@ -46,10 +46,8 @@ const looseEqual = (a, b) => { return false } for (const key in a) { - // eslint-disable-next-line no-prototype-builtins - const aHasKey = a.hasOwnProperty(key) - // eslint-disable-next-line no-prototype-builtins - const bHasKey = b.hasOwnProperty(key) + const aHasKey = hasOwnProperty(a, key) + const bHasKey = hasOwnProperty(b, key) if ((aHasKey && !bHasKey) || (!aHasKey && bHasKey) || !looseEqual(a[key], b[key])) { return false } From daafacddbc4e897acde88508583c97abaceb7ad5 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Mon, 25 May 2020 11:51:39 -0300 Subject: [PATCH 3/3] Update form-checkbox-group.spec.js --- .../form-checkbox/form-checkbox-group.spec.js | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/components/form-checkbox/form-checkbox-group.spec.js b/src/components/form-checkbox/form-checkbox-group.spec.js index f9e12de616b..a5abcf0f125 100644 --- a/src/components/form-checkbox/form-checkbox-group.spec.js +++ b/src/components/form-checkbox/form-checkbox-group.spec.js @@ -363,6 +363,54 @@ describe('form-checkbox-group', () => { wrapper.destroy() }) + it('does not emit "input" event when value loosely changes', async () => { + const value = ['one', 'two', 'three'] + const wrapper = mount(BFormCheckboxGroup, { + attachTo: createContainer(), + propsData: { + options: value.slice(), + checked: value.slice() + } + }) + expect(wrapper.classes()).toBeDefined() + const checks = wrapper.findAll('input') + expect(checks.length).toBe(3) + expect(wrapper.vm.localChecked).toEqual(value) + expect(checks.wrappers.every(c => c.find('input[type=checkbox]').exists())).toBe(true) + expect(checks.at(0).element.checked).toBe(true) + expect(checks.at(1).element.checked).toBe(true) + expect(checks.at(2).element.checked).toBe(true) + + expect(wrapper.emitted('input')).not.toBeDefined() + + // Set internal value to new array reference + wrapper.vm.localChecked = value.slice() + await waitNT(wrapper.vm) + + expect(wrapper.vm.localChecked).toEqual(value) + expect(checks.wrappers.every(c => c.find('input[type=checkbox]').exists())).toBe(true) + expect(checks.at(0).element.checked).toBe(true) + expect(checks.at(1).element.checked).toBe(true) + expect(checks.at(2).element.checked).toBe(true) + + expect(wrapper.emitted('input')).not.toBeDefined() + + // Set internal value to new array (reversed order) + wrapper.vm.localChecked = value.slice().reverse() + await waitNT(wrapper.vm) + + expect(wrapper.vm.localChecked).toEqual(value.slice().reverse()) + expect(checks.wrappers.every(c => c.find('input[type=checkbox]').exists())).toBe(true) + expect(checks.at(0).element.checked).toBe(true) + expect(checks.at(1).element.checked).toBe(true) + expect(checks.at(2).element.checked).toBe(true) + expect(wrapper.emitted('input')).toBeDefined() + expect(wrapper.emitted('input').length).toBe(1) + expect(wrapper.emitted('input')[0][0]).toEqual(value.slice().reverse()) + + wrapper.destroy() + }) + it('checkboxes reflect group checked v-model', async () => { const wrapper = mount(BFormCheckboxGroup, { attachTo: createContainer(),