Skip to content

Commit

Permalink
switch: add beforeChange hook (#1878)
Browse files Browse the repository at this point in the history
  • Loading branch information
SorrowX committed Apr 26, 2021
1 parent 045ea5d commit a1f521e
Show file tree
Hide file tree
Showing 7 changed files with 716 additions and 308 deletions.
102 changes: 102 additions & 0 deletions packages/switch/__tests__/switch.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { mount } from '@vue/test-utils'
import Switch from '../src/index.vue'
import { nextTick } from 'vue'

jest.useFakeTimers()

describe('Switch.vue', () => {

Expand Down Expand Up @@ -228,4 +231,103 @@ describe('Switch.vue', () => {
await vm.$nextTick()
expect(inputEl.checked).toEqual(false)
})

test('beforeChange function return promise', async () => {
const wrapper = mount({
components: {
'el-switch': Switch,
},
template: `
<div>
<el-switch
v-model="value"
:loading="loading"
:before-change="beforeChange"
/>
</div>
`,
data() {
return {
value: true,
loading: false,
asyncResult: 'error',
}
},
methods: {
beforeChange() {
this.loading = true
return new Promise((resolve, reject) => {
setTimeout(() => {
this.loading = false
return this.asyncResult == 'success'
? resolve(true)
: reject(new Error('error'))
}, 1000)
})
},
},
})
const vm = wrapper.vm

const coreWrapper = wrapper.find('.el-switch__core')

coreWrapper.trigger('click')
jest.runAllTimers()
await nextTick()
expect(vm.value).toEqual(true)

vm.asyncResult = 'success'

coreWrapper.trigger('click')
jest.runAllTimers()
await nextTick()
expect(vm.value).toEqual(false)

coreWrapper.trigger('click')
jest.runAllTimers()
await nextTick()
expect(vm.value).toEqual(true)
})

test('beforeChange function return boolean', async () => {
const wrapper = mount({
components: {
'el-switch': Switch,
},
template: `
<div>
<el-switch
v-model="value"
:before-change="beforeChange"
/>
</div>
`,
data() {
return {
value: true,
result: false,
}
},
methods: {
beforeChange() {
// do something ...
return this.result
},
},
})
const vm = wrapper.vm

const coreWrapper = wrapper.find('.el-switch__core')

await coreWrapper.trigger('click')
expect(vm.value).toEqual(true)

vm.result = true

await coreWrapper.trigger('click')
expect(vm.value).toEqual(false)

await coreWrapper.trigger('click')
expect(vm.value).toEqual(true)
})
})
42 changes: 41 additions & 1 deletion packages/switch/src/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@
<script lang='ts'>
import { defineComponent, computed, onMounted, ref, inject, nextTick, watch } from 'vue'
import { elFormKey, elFormItemKey } from '@element-plus/form'
import { isPromise } from '@vue/shared'
import { isBool } from '@element-plus/utils/util'
import throwError, { warn } from '@element-plus/utils/error'
import type { ElFormContext, ElFormItemContext } from '@element-plus/form'
import type { PropType } from 'vue'
type ValueType = boolean | string | number;
Expand All @@ -66,6 +70,7 @@ interface ISwitchProps {
validateEvent: boolean
id: string
loading:boolean
beforeChange?: () => (Promise<boolean> | boolean)
}
export default defineComponent({
Expand Down Expand Up @@ -132,6 +137,7 @@ export default defineComponent({
type: Boolean,
default: false,
},
beforeChange: Function as PropType<() => (Promise<boolean> | boolean)>,
},
emits: ['update:modelValue', 'change', 'input'],
setup(props: ISwitchProps, ctx) {
Expand All @@ -142,6 +148,8 @@ export default defineComponent({
const input = ref(null)
const core = ref(null)
const scope = 'ElSwitch'
watch(() => props.modelValue, () => {
isModelValue.value = true
})
Expand Down Expand Up @@ -191,7 +199,34 @@ export default defineComponent({
}
const switchValue = (): void => {
!switchDisabled.value && handleChange()
if (switchDisabled.value) return
const { beforeChange } = props
if (!beforeChange) {
handleChange()
return
}
const shouldChange = beforeChange()
const isExpectType = [isPromise(shouldChange), isBool(shouldChange)].some(i => i)
if (!isExpectType) {
throwError(scope, 'beforeChange must return type `Promise<boolean>` or `boolean`')
}
if (isPromise(shouldChange)) {
shouldChange.then(result => {
if (result) {
handleChange()
}
}).catch(e => {
if (process.env.NODE_ENV !== 'production') {
warn(scope, `some error occurred: ${e}`)
}
})
} else if (shouldChange) {
handleChange()
}
}
const setBackgroundColor = (): void => {
Expand All @@ -202,6 +237,10 @@ export default defineComponent({
coreEl.children[0].style.color = newColor
}
const focus = (): void => {
input.value?.focus?.()
}
onMounted(() => {
if (props.activeValue || props.inactiveValue) {
setBackgroundColor()
Expand All @@ -217,6 +256,7 @@ export default defineComponent({
checked,
handleChange,
switchValue,
focus,
}
},
})
Expand Down
Loading

0 comments on commit a1f521e

Please sign in to comment.