mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
fix(components): [date-picker]: use array modelValue datetime type debacle (#22033)
fix(components): [date-picker]: use array value datetime type debacle
This commit is contained in:
@@ -461,6 +461,24 @@ describe('DatePickerPanel', () => {
|
||||
'6',
|
||||
])
|
||||
})
|
||||
|
||||
it('should handle array value without errors', async () => {
|
||||
const value = ref(['2025-09-01'])
|
||||
const wrapper = mount(() => (
|
||||
<DatePickerPanel v-model={value.value} type="datetime" />
|
||||
))
|
||||
await nextTick()
|
||||
|
||||
const dateInput = wrapper.find(
|
||||
'.el-date-picker__time-header > span:nth-child(1) input'
|
||||
).element as HTMLInputElement
|
||||
expect(dateInput.value).toBe('2025-09-01')
|
||||
|
||||
const timeInput = wrapper.find(
|
||||
'.el-date-picker__time-header > span:nth-child(2) input'
|
||||
).element as HTMLInputElement
|
||||
expect(timeInput.value).toBe('00:00:00')
|
||||
})
|
||||
})
|
||||
|
||||
describe(':type="datetimerange"', () => {
|
||||
|
||||
@@ -236,7 +236,7 @@ import {
|
||||
extractTimeFormat,
|
||||
} from '@element-plus/components/time-picker'
|
||||
import { ElIcon } from '@element-plus/components/icon'
|
||||
import { isArray, isFunction } from '@element-plus/utils'
|
||||
import { extractFirst, isArray, isFunction } from '@element-plus/utils'
|
||||
import { EVENT_CODE } from '@element-plus/constants'
|
||||
import {
|
||||
ArrowLeft,
|
||||
@@ -347,8 +347,9 @@ const emit = (value: Dayjs | Dayjs[], ...args: any[]) => {
|
||||
const handleDatePick = async (value: DateTableEmits, keepOpen?: boolean) => {
|
||||
if (selectionMode.value === 'date') {
|
||||
value = value as Dayjs
|
||||
let newDate = props.parsedValue
|
||||
? (props.parsedValue as Dayjs)
|
||||
const parsedDateValue = extractFirst(props.parsedValue)
|
||||
let newDate = parsedDateValue
|
||||
? parsedDateValue
|
||||
.year(value.year())
|
||||
.month(value.month())
|
||||
.date(value.date())
|
||||
@@ -547,7 +548,7 @@ const onConfirm = () => {
|
||||
emit(props.parsedValue as Dayjs[])
|
||||
} else {
|
||||
// deal with the scenario where: user opens the date time picker, then confirm without doing anything
|
||||
let result = props.parsedValue as Dayjs
|
||||
let result = extractFirst(props.parsedValue)
|
||||
if (!result) {
|
||||
const defaultTimeD = dayjs(defaultTime).locale(lang.value)
|
||||
const defaultValueD = getDefaultValue()
|
||||
@@ -595,17 +596,15 @@ const dateFormat = computed(() => {
|
||||
const visibleTime = computed(() => {
|
||||
if (userInputTime.value) return userInputTime.value
|
||||
if (!props.parsedValue && !defaultValue.value) return
|
||||
return ((props.parsedValue || innerDate.value) as Dayjs).format(
|
||||
timeFormat.value
|
||||
)
|
||||
const dateValue = extractFirst(props.parsedValue) || innerDate.value
|
||||
return dateValue.format(timeFormat.value)
|
||||
})
|
||||
|
||||
const visibleDate = computed(() => {
|
||||
if (userInputDate.value) return userInputDate.value
|
||||
if (!props.parsedValue && !defaultValue.value) return
|
||||
return ((props.parsedValue || innerDate.value) as Dayjs).format(
|
||||
dateFormat.value
|
||||
)
|
||||
const dateValue = extractFirst(props.parsedValue) || innerDate.value
|
||||
return dateValue.format(dateFormat.value)
|
||||
})
|
||||
|
||||
const timePickerVisible = ref(false)
|
||||
@@ -629,8 +628,9 @@ const getUnits = (date: Dayjs) => {
|
||||
|
||||
const handleTimePick = (value: Dayjs, visible: boolean, first: boolean) => {
|
||||
const { hour, minute, second } = getUnits(value)
|
||||
const newDate = props.parsedValue
|
||||
? (props.parsedValue as Dayjs).hour(hour).minute(minute).second(second)
|
||||
const parsedDateValue = extractFirst(props.parsedValue)
|
||||
const newDate = parsedDateValue
|
||||
? parsedDateValue.hour(hour).minute(minute).second(second)
|
||||
: value
|
||||
innerDate.value = newDate
|
||||
emit(innerDate.value, true)
|
||||
|
||||
@@ -1096,6 +1096,54 @@ describe('DatePicker', () => {
|
||||
expect(changeHandler).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle array value for datetime type without errors', async () => {
|
||||
const wrapper = _mount(
|
||||
`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetime"
|
||||
/>`,
|
||||
() => ({ value: ['2025-09-01'] })
|
||||
)
|
||||
|
||||
await nextTick()
|
||||
const input = wrapper.find('input')
|
||||
expect(input.element.value).toBe('2025-09-01 00:00:00')
|
||||
|
||||
await input.trigger('focus')
|
||||
await nextTick()
|
||||
|
||||
const dateInput = document.querySelector(
|
||||
'.el-date-picker__time-header > span:nth-child(1) input'
|
||||
) as HTMLInputElement
|
||||
const timeInput = document.querySelector(
|
||||
'.el-date-picker__time-header > span:nth-child(2) input'
|
||||
) as HTMLInputElement
|
||||
|
||||
expect(dateInput?.value).toBe('2025-09-01')
|
||||
expect(timeInput?.value).toBe('00:00:00')
|
||||
})
|
||||
|
||||
it('should convert array value to proper format when changed', async () => {
|
||||
const wrapper = _mount(
|
||||
`<el-date-picker v-model="value" type="datetime" />`,
|
||||
() => ({ value: ['2025-09-04'] })
|
||||
)
|
||||
|
||||
const originalValue = wrapper.vm.value
|
||||
expect(originalValue).toEqual(['2025-09-04'])
|
||||
|
||||
const input = wrapper.find('input')
|
||||
await input.trigger('focus')
|
||||
await nextTick()
|
||||
|
||||
const dateCell = document.querySelector('.el-date-table td.available')
|
||||
await (dateCell as HTMLElement)?.click()
|
||||
await nextTick()
|
||||
|
||||
expect(wrapper.vm.value).not.toEqual(['2025-09-04'])
|
||||
expect(Array.isArray(wrapper.vm.value)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('DatePicker Navigation', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { castArray as lodashCastArray } from 'lodash-unified'
|
||||
import { castArray, ensureArray, unique } from '..'
|
||||
import { castArray, ensureArray, extractFirst, unique } from '..'
|
||||
|
||||
describe('arrays', () => {
|
||||
it('unique should work', () => {
|
||||
@@ -17,4 +17,14 @@ describe('arrays', () => {
|
||||
it('re-export ensureArray', () => {
|
||||
expect(ensureArray).toBe(lodashCastArray)
|
||||
})
|
||||
|
||||
it('extractFirst should work', () => {
|
||||
expect(extractFirst([1, 2, 3])).toBe(1)
|
||||
expect(extractFirst(['a', 'b', 'c'])).toBe('a')
|
||||
expect(extractFirst(42)).toBe(42)
|
||||
expect(extractFirst('hello')).toBe('hello')
|
||||
expect(extractFirst(null)).toBe(null)
|
||||
expect(extractFirst(undefined)).toBe(undefined)
|
||||
expect(extractFirst([])).toBe(undefined)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,6 +2,10 @@ import { isArray } from './types'
|
||||
|
||||
export const unique = <T>(arr: T[]) => [...new Set(arr)]
|
||||
|
||||
export const extractFirst = <T>(arr: T | T[]): T => {
|
||||
return isArray(arr) ? arr[0] : arr
|
||||
}
|
||||
|
||||
type Many<T> = T | ReadonlyArray<T>
|
||||
// TODO: rename to `ensureArray`
|
||||
/** like `_.castArray`, except falsy value returns empty array. */
|
||||
|
||||
Reference in New Issue
Block a user