nuxt / ui

A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.
https://ui.nuxt.com
MIT License
4.09k stars 535 forks source link

Need help: `DatePicker` set value not work #2106

Open dncmaduro opened 2 months ago

dncmaduro commented 2 months ago

Environment

Version

v2.18.2

Reproduction

Just a small question, no need to reproduce

Description

This is my DatePicker component

<template>
  <VCalendarDatePicker v-if="date" v-bind="{ ...attrs, ...$attrs }" />
</template>

<script setup lang="ts">
import { DatePicker as VCalendarDatePicker } from 'v-calendar'
import type { DatePickerDate } from 'v-calendar/dist/types/src/use/datePicker'
import 'v-calendar/dist/style.css'

const props = defineProps({
  modelValue: {
    type: Date as PropType<DatePickerDate>,
    default: null
  }
})

const emit = defineEmits(['update:model-value', 'close'])

const date = computed({
  get: () => props.modelValue,
  set: (value) => {
    emit('update:model-value', value)
    emit('close')
  }
})

const attrs = {
  transparent: true,
  borderless: true,
  color: 'primary',
  'is-dark': { selector: 'html', darkClass: 'dark' },
  'first-day-of-week': 1
}
</script>

And I use this component like this:

<template>
  <PagesForm
    :title="title"
    :action="action"
    @submit="formRef.submit()"
    :submit-button-label="submitButtonLabel"
  >
    <UForm
      :validate="validate"
      :state="state"
      class="flex w-full flex-col gap-8"
      @error="onError"
      @submit="onSubmit"
      ref="formRef"
    >
      <UFormGroup label="Name" name="name" required>
        <UInput placeholder="Enter member name..." size="xl" v-model="state.name" />
      </UFormGroup>

      <UFormGroup label="Email" name="email" required>
        <UInput placeholder="Enter member email..." size="xl" v-model="state.email" />
      </UFormGroup>

      <UFormGroup label="School" name="school" required>
        <UInput placeholder="Enter member school..." size="xl" v-model="state.school" />
      </UFormGroup>

      <UFormGroup label="Position" name="position" required>
        <USelect
          placeholder="Select"
          size="xl"
          v-model="state.position"
          :options="positionOptions"
        />
      </UFormGroup>

      <UFormGroup label="Joined At" name="joinedAt" required>
        <UPopover :popper="{ placement: 'bottom-start' }" class="w-full">
          <UButton
            icon="i-heroicons-calendar-days"
            :label="format(state.joinedAt || new Date(), 'd MMM, yyy')"
            color="white"
            class="w-full"
            size="xl"
          />

          <template #panel="{ close }">
            <CommonDatePicker v-model="state.joinedAt" @close="close" />
          </template>
        </UPopover>
      </UFormGroup>
    </UForm>
  </PagesForm>
</template>

<script setup lang="ts">
import { format } from 'date-fns'
import type { FormSubmitEvent, FormError, FormErrorEvent } from '#ui/types'
import { positionOptions } from '~/constants/select-options/positions'
import type { MemberForm, MemberFormState } from '~/types/members'

const props = defineProps<MemberForm>()

const formRef = ref()

const state = reactive<MemberFormState>({
  name: props.form?.name || '',
  email: props.form?.email || '',
  school: props.form?.school || '',
  position: props.form?.position || '',
  joinedAt: props.form?.joinedAt || new Date(),
  gen: props.form?.gen || undefined,
  aboutThisMember: props.form?.aboutThisMember || '',
  facebook: props.form?.facebook || '',
  github: props.form?.github || '',
  linkedin: props.form?.linkedin || ''
})

const validate = (state: MemberFormState): FormError[] => {
  const errors = []
  if (!state.name) errors.push({ path: 'name', message: 'Required' })
  if (!state.email) errors.push({ path: 'email', message: 'Required' })
  if (!state.school) errors.push({ path: 'school', message: 'Required' })
  if (!state.position) errors.push({ path: 'position', message: 'Required' })
  if (!state.joinedAt) errors.push({ path: 'joinedAt', message: 'Required' })
  if (!state.gen) errors.push({ path: 'gen', message: 'Required' })
  if (!state.aboutThisMember) errors.push({ path: 'aboutThisMember', message: 'Required' })
  if (!state.facebook) errors.push({ path: 'facebook', message: 'Required' })
  if (!state.github) errors.push({ path: 'joinedAt', message: 'Required' })
  if (!state.linkedin) errors.push({ path: 'linkedin', message: 'Required' })
  return errors
}

const onError = async (event: FormErrorEvent) => {
  const element = document.getElementById(event.errors[0].id)
  element?.focus()
  element?.scrollIntoView({ behavior: 'smooth', block: 'center' })
}

const emit = defineEmits<{
  (e: 'form-submit', data: object): void
}>()

const onSubmit = async (event: FormSubmitEvent<MemberFormState>) => {
  emit('form-submit', event.data)
}
</script>

When I click the button, the DatePicker is shown but the label of the Button is not change. I still don't know that caused by the date is not changed or I set the label of the button wrongly. But when I put a console.log inside the set(), it does not run. image

Additional context

No response

Logs

No response

clopezpro commented 1 week ago

The same thing happened to me, but I solved it like this in script setup create const multiplePicker = ref<DatePickerContext | null>(null) and watch const multiplePicker = ref<DatePickerContext | null>(null) watch(() => props.modelValue, async () => { if (multiplePicker.value) await multiplePicker.value.moveToValue('start') })

in component add ref="multiplePicker" <VCalendarDatePicker v-if="date && (typeof date === 'object')" ref="multiplePicker" v-model.range="date" :columns="2" v-bind="{ ...attrs, ...$attrs }" />

execute the moveToValue function so that v-calendar updates the calendar