Skip to content

Commit

Permalink
feat(useVModel): add option to define defaultValue (#1537)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
sondh0127 and antfu committed May 3, 2022
1 parent e8c057c commit 66e82ec
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 5 deletions.
18 changes: 18 additions & 0 deletions packages/core/useVModel/index.test.ts
Expand Up @@ -93,4 +93,22 @@ describe('useVModel', () => {
expect(emitMock).toBeCalledTimes(1)
expect(emitMock).toHaveBeenCalledWith('update:data', { hobbies: ['coding', 'basketball'] })
})

it('should work with user define defaultValue', () => {
const props = {
...defaultProps(),
}
const emitMock = vitest.fn()
const data = useVModel(props, 'data', emitMock, { defaultValue: 'default-data' })
expect(data.value).toBe('default-data')
})

it('should work with user define defaultValue with passive', () => {
const props = {
...defaultProps(),
}
const emitMock = vitest.fn()
const data = useVModel(props, 'data', emitMock, { passive: true, defaultValue: 'default-data' })
expect(data.value).toBe('default-data')
})
})
15 changes: 11 additions & 4 deletions packages/core/useVModel/index.ts
@@ -1,7 +1,7 @@
import type { UnwrapRef } from 'vue-demi'
import { computed, getCurrentInstance, isVue2, ref, watch } from 'vue-demi'

export interface VModelOptions {
export interface VModelOptions<T> {
/**
* When passive is set to `true`, it will use `watch` to sync with props and ref.
* Instead of relying on the `v-model` or `.sync` to work.
Expand All @@ -21,6 +21,12 @@ export interface VModelOptions {
* @default false
*/
deep?: boolean
/**
* Defining default value for return ref when no value is passed.
*
* @default undefined
*/
defaultValue?: T
}

/**
Expand All @@ -35,12 +41,13 @@ export function useVModel<P extends object, K extends keyof P, Name extends stri
props: P,
key?: K,
emit?: (name: Name, ...args: any[]) => void,
options: VModelOptions = {},
options: VModelOptions<P[K]> = {},
) {
const {
passive = false,
eventName,
deep = false,
defaultValue,
} = options

const vm = getCurrentInstance()
Expand All @@ -63,7 +70,7 @@ export function useVModel<P extends object, K extends keyof P, Name extends stri
event = eventName || event || `update:${key}`

if (passive) {
const proxy = ref<P[K]>(props[key!])
const proxy = ref<P[K]>(props[key!] || defaultValue!)

watch(() => props[key!], v => proxy.value = v as UnwrapRef<P[K]>)

Expand All @@ -79,7 +86,7 @@ export function useVModel<P extends object, K extends keyof P, Name extends stri
else {
return computed<P[K]>({
get() {
return props[key!]
return props[key!] || defaultValue!
},
set(value) {
_emit(event, value)
Expand Down
2 changes: 1 addition & 1 deletion packages/core/useVModels/index.ts
Expand Up @@ -12,7 +12,7 @@ import { useVModel } from '../useVModel'
export function useVModels<P extends object, Name extends string>(
props: P,
emit?: (name: Name, ...args: any[]) => void,
options: VModelOptions = {},
options: VModelOptions<any> = {},
): ToRefs<P> {
const ret: any = {}
// eslint-disable-next-line no-restricted-syntax
Expand Down

0 comments on commit 66e82ec

Please sign in to comment.