Skip to content

Commit

Permalink
fix(b-form-checkbox-group): only emit input when value loosely chan…
Browse files Browse the repository at this point in the history
…ges (#5432)

* fix(b-form-checkbox-group, b-form-radio-group): only emit `input` when value loosely changes

* Update loose-equal.js

* Update form-checkbox-group.spec.js
  • Loading branch information
tmorehouse committed May 25, 2020
1 parent a4dbf7f commit e76d408
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 7 deletions.
48 changes: 48 additions & 0 deletions src/components/form-checkbox/form-checkbox-group.spec.js
Expand Up @@ -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(),
Expand Down
7 changes: 5 additions & 2 deletions 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'
Expand Down Expand Up @@ -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) {
Expand Down
8 changes: 3 additions & 5 deletions 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!
Expand Down Expand Up @@ -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
}
Expand Down

1 comment on commit e76d408

@vercel
Copy link

@vercel vercel bot commented on e76d408 May 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.