Skip to content

Commit

Permalink
feat(useVModel): add shouldEmit hook (#2836)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
baiwusanyu-c and antfu committed Mar 23, 2023
1 parent f4d3542 commit f8a5328
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 2 deletions.
36 changes: 36 additions & 0 deletions packages/core/useVModel/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,40 @@ describe('useVModel', () => {
child: { age: 2 },
})
})

it('should trigger beforeEmit', async () => {
const emitMock = vitest.fn()
const beforeEmitMock = vitest.fn()
let res = ''
const beforeEmit = (value: string) => {
res = value
beforeEmitMock()
return true
}
const data = useVModel(defaultProps(), undefined, emitMock, { shouldEmit: beforeEmit })
data.value = 'changed'

expect(emitMock).toHaveBeenCalledWith(isVue2 ? 'input' : 'update:modelValue', 'changed')
expect(beforeEmitMock).toHaveBeenCalled()
await nextTick()
expect(res).toBe('changed')
})

it('should not trigger beforeEmit (return false)', async () => {
const emitMock = vitest.fn()
const beforeEmitMock = vitest.fn()
let res = ''
const beforeEmit = (value: string) => {
res = value
beforeEmitMock()
return false
}
const data = useVModel(defaultProps(), undefined, emitMock, { shouldEmit: beforeEmit })
data.value = 'changed'

expect(emitMock).not.toHaveBeenCalled()
expect(beforeEmitMock).toHaveBeenCalled()
await nextTick()
expect(res).toBe('changed')
})
})
22 changes: 20 additions & 2 deletions packages/core/useVModel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ export interface UseVModelOptions<T> {
* @default false
*/
clone?: boolean | CloneFn<T>
/**
* The hook before triggering the emit event can be used for form validation.
* if false is returned, the emit event will not be triggered.
*
* @default undefined
*/
shouldEmit?: (v: T) => boolean
}

/**
Expand All @@ -61,6 +68,7 @@ export function useVModel<P extends object, K extends keyof P, Name extends stri
eventName,
deep = false,
defaultValue,
shouldEmit,
} = options

const vm = getCurrentInstance()
Expand Down Expand Up @@ -92,6 +100,16 @@ export function useVModel<P extends object, K extends keyof P, Name extends stri
? cloneFn(props[key!])
: defaultValue

const triggerEmit = (value: P[K]) => {
if (shouldEmit) {
if (shouldEmit(value))
_emit(event, value)
}
else {
_emit(event, value)
}
}

if (passive) {
const initialValue = getValue()
const proxy = ref<P[K]>(initialValue!)
Expand All @@ -105,7 +123,7 @@ export function useVModel<P extends object, K extends keyof P, Name extends stri
proxy,
(v) => {
if (v !== props[key!] || deep)
_emit(event, v)
triggerEmit(v as P[K])
},
{ deep },
)
Expand All @@ -118,7 +136,7 @@ export function useVModel<P extends object, K extends keyof P, Name extends stri
return getValue()!
},
set(value) {
_emit(event, value)
triggerEmit(value)
},
})
}
Expand Down

0 comments on commit f8a5328

Please sign in to comment.