Search code examples
reactjsreact-nativecomboboxnextjs14shadcnui

ShadCN UI combobox, how to passing data from them?


i have a component combobox shadcn with nextjs, the components put in the form, how i can see the value like id='student' name='student' in console.log when submit

this my sourcecode

"use client"

import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import * as React from 'react'

import { Check, ChevronsUpDown } from "lucide-react"

import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from "@/components/ui/command"
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"
import SubmitButtonForm from '../../components/submit-form-button'
import { Airplane } from '@prisma/client'
import { useFormState } from 'react-dom'
import { saveFlight } from '../lib/action'
import { ActionResult } from '@/app/dashboard/(auth)/signin/form/action'

interface FormFlightProps {
  airplanes: Airplane[]
}

const initialFormState: ActionResult = {
  errorTitle: null,
  errorDesc: []
}

export default function FormFlight({ airplanes }: FormFlightProps) {

  // console.log(airplanes)

  // const frameworks = [
  //   {
  //     planeId: 1,
  //     value: "next.js",
  //     label: "Next.js",
  //   },
  //   {
  //     planeId: 2,
  //     value: "sveltekit",
  //     label: "SvelteKit",
  //   },
  //   {
  //     planeId: 3,
  //     value: "nuxt.js",
  //     label: "Nuxt.js",
  //   },
  //   {
  //     planeId: 4,
  //     value: "remix",
  //     label: "Remix",
  //   },
  //   {
  //     planeId: 5,
  //     value: "astro",
  //     label: "Astro",
  //   },
  // ]

  const [state, formAction] = useFormState(saveFlight, initialFormState)

  function ComboboxDemo() {
    const [open, setOpen] = React.useState(false)
    const [value, setValue] = React.useState("")

    return (
      <Popover open={open} onOpenChange={setOpen}>
        <PopoverTrigger asChild>
          <Button
            variant="outline"
            role="combobox"
            aria-expanded={open}
            className="w-[100%] justify-between mt-8"
          >
            {value
              ? airplanes.find((airplane) => airplane.name === value)?.name
              : "Pilih Pesawat..."}
            <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
          </Button>
        </PopoverTrigger>
        <PopoverContent className="w-[250px] md:w-[370px] lg:w-[640px] p-0">
          <Command>
            <CommandInput placeholder="Cari Pesawat/Penerbangan..." />
            <CommandList>
              <CommandEmpty>Pesawat/Penerbangan tidak ditemukan.</CommandEmpty>
              <CommandGroup>
                {airplanes.map((airplane) => (
                  <CommandItem
                    key={airplane.id}
                    value={airplane.name}
                    onSelect={(currentValue) => {
                      setValue(currentValue === value ? "" : currentValue)
                      setOpen(false)

                    }}
                  >
                    <Check
                      className={cn(
                        "mr-2 h-4 w-4",
                        value === airplane.id ? "opacity-100" : "opacity-0"
                      )}
                    />
                    {airplane.name}
                  </CommandItem>
                ))}
              </CommandGroup>
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>
    )
  }

  return (
    <form action={formAction} className='space-y-6'>
      <div className='grid grid-cols-2 gap-4'>
        <div className='space-y-2'>
          <Label htmlFor="planeId">Pilih Pesawat</Label>
          <ComboboxDemo />
          {/* <Input
            // placeholder="Harga Tiket..."
            type='hidden'
            name="planeId"
            id="planeId"
            value={'test'}
            required
          /> */}
        </div>

        <div className="space-y-2">
          <Label htmlFor="price">Harga Tiket</Label>
          <Input
            placeholder="Harga Tiket..."
            name="price"
            id="price"
            type='number'
            min={0}
            required
          />
          <span className="text-xs text-gray-900">
            *Kelas Bisnis ++ Rp 500.000, Kelas First ++ Rp 750.000*
          </span>
        </div>
      </div>
      <div className="grid grid-cols-3 gap-4">
        <div className="space-y-2">
          <Label htmlFor="departureCity">Kota Keberangkatan</Label>
          <Input
            placeholder="Kota Keberangkatan..."
            name="departureCity"
            id="departureCity"
            required
          />
        </div>
        <div className="space-y-2">
          <Label htmlFor="departureDate">Tanggal Keberangkatan</Label>
          <Input
            type='datetime-local'
            placeholder="Tanggal Keberangkatan..."
            name="departureDate"
            id="departureDate"
            className='block'
            required
          />
        </div>
        <div className="space-y-2">
          <Label htmlFor="departureCityCode">Kode Kota</Label>
          <Input
            placeholder="Kode Kota..."
            name="departureCityCode"
            id="departureCityCode"
            required
          />
        </div>
      </div>
      <div className="grid grid-cols-3 gap-4">
        <div className="space-y-2">
          <Label htmlFor="destinationCity">Kota Tujuan</Label>
          <Input
            placeholder="Kota Tujuan..."
            name="destinationCity"
            id="destinationCity"
            required
          />
        </div>
        <div className="space-y-2">
          <Label htmlFor="arrivalDate">Tanggal Tiba</Label>
          <Input
            type='datetime-local'
            placeholder="Tanggal Tiba..."
            name="arrivalDate"
            id="arrivalDate"
            className='block'
            required
          />
        </div>
        <div className="space-y-2">
          <Label htmlFor="destinationCityCode">Kode Kota</Label>
          <Input
            placeholder="Kode Kota..."
            name="destinationCityCode"
            id="destinationCityCode"
            required
          />
        </div>
      </div>

      <SubmitButtonForm />
    </form>
  )
}

i want when i console.log formData after submit is exist like below

FormData {
  '$ACTION_REF_2': '',
  '$ACTION_2:0': '{"id":"eee2f8c376832dd5ff345bf9d7d9b86748644191","bound":"$@1"}',
  '$ACTION_2:1': '[{"errorTitle":null,"errorDesc":[]}]',
  '$ACTION_KEY': 'k3995036715',
  **planeId: 'test',** <---- like here
  price: '1234567',
  departureCity: 'Bandung',
  departureDate: '2024-09-15T16:28',
  departureCityCode: 'BDG',
  destinationCity: 'Jakarta',
  arrivalDate: '2024-09-15T22:28',
  destinationCityCode: 'JKT'
}

I have tried adding the name and id to the Item command but when I look at the console.log it doesn't appear


Solution

  • you need to manage the state properly and ensure that this state is reflected in a hidden input field that will be included in the form data.

    You'll need to add a hidden input field to your form to capture the value selected in the ComboboxDemo component. This field should be updated whenever the selection changes. when a selection is made in the ComboboxDemo, the hidden input field's value is updated accordingly.

        "use client"
    
    import { Input } from '@/components/ui/input'
    import { Label } from '@/components/ui/label'
    import * as React from 'react'
    import { Check, ChevronsUpDown } from "lucide-react"
    import { cn } from "@/lib/utils"
    import { Button } from "@/components/ui/button"
    import {
      Command,
      CommandEmpty,
      CommandGroup,
      CommandInput,
      CommandItem,
      CommandList,
    } from "@/components/ui/command"
    import {
      Popover,
      PopoverContent,
      PopoverTrigger,
    } from "@/components/ui/popover"
    import SubmitButtonForm from '../../components/submit-form-button'
    import { Airplane } from '@prisma/client'
    import { useFormState } from 'react-dom'
    import { saveFlight } from '../lib/action'
    import { ActionResult } from '@/app/dashboard/(auth)/signin/form/action'
    
    interface FormFlightProps {
      airplanes: Airplane[]
    }
    
    const initialFormState: ActionResult = {
      errorTitle: null,
      errorDesc: []
    }
    
    export default function FormFlight({ airplanes }: FormFlightProps) {
    
      const [state, formAction] = useFormState(saveFlight, initialFormState)
    
      function ComboboxDemo() {
        const [open, setOpen] = React.useState(false)
        const [value, setValue] = React.useState<string>("")
    
        // Update the hidden input field with the selected value
        React.useEffect(() => {
          const hiddenInput = document.getElementById('planeId') as HTMLInputElement
          if (hiddenInput) {
            hiddenInput.value = value
          }
        }, [value])
    
        return (
          <Popover open={open} onOpenChange={setOpen}>
            <PopoverTrigger asChild>
              <Button
                variant="outline"
                role="combobox"
                aria-expanded={open}
                className="w-[100%] justify-between mt-8"
              >
                {value
                  ? airplanes.find((airplane) => airplane.name === value)?.name
                  : "Pilih Pesawat..."}
                <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
              </Button>
            </PopoverTrigger>
            <PopoverContent className="w-[250px] md:w-[370px] lg:w-[640px] p-0">
              <Command>
                <CommandInput placeholder="Cari Pesawat/Penerbangan..." />
                <CommandList>
                  <CommandEmpty>Pesawat/Penerbangan tidak ditemukan.</CommandEmpty>
                  <CommandGroup>
                    {airplanes.map((airplane) => (
                      <CommandItem
                        key={airplane.id}
                        value={airplane.name}
                        onSelect={(currentValue) => {
                          setValue(currentValue === value ? "" : currentValue)
                          setOpen(false)
                        }}
                      >
                        <Check
                          className={cn(
                            "mr-2 h-4 w-4",
                            value === airplane.name ? "opacity-100" : "opacity-0"
                          )}
                        />
                        {airplane.name}
                      </CommandItem>
                    ))}
                  </CommandGroup>
                </CommandList>
              </Command>
            </PopoverContent>
          </Popover>
        )
      }
    
      return (
        <form action={formAction} className='space-y-6'>
          <div className='grid grid-cols-2 gap-4'>
            <div className='space-y-2'>
              <Label htmlFor="planeId">Pilih Pesawat</Label>
              <ComboboxDemo />
              <Input
                type='hidden'
                name="planeId"
                id="planeId"
                required
              />
            </div>
    
            <div className="space-y-2">
              <Label htmlFor="price">Harga Tiket</Label>
              <Input
                placeholder="Harga Tiket..."
                name="price"
                id="price"
                type='number'
                min={0}
                required
              />
              <span className="text-xs text-gray-900">
                *Kelas Bisnis ++ Rp 500.000, Kelas First ++ Rp 750.000*
              </span>
            </div>
          </div>
          <div className="grid grid-cols-3 gap-4">
            <div className="space-y-2">
              <Label htmlFor="departureCity">Kota Keberangkatan</Label>
              <Input
                placeholder="Kota Keberangkatan..."
                name="departureCity"
                id="departureCity"
                required
              />
            </div>
            <div className="space-y-2">
              <Label htmlFor="departureDate">Tanggal Keberangkatan</Label>
              <Input
                type='datetime-local'
                placeholder="Tanggal Keberangkatan..."
                name="departureDate"
                id="departureDate"
                className='block'
                required
              />
            </div>
            <div className="space-y-2">
              <Label htmlFor="departureCityCode">Kode Kota</Label>
              <Input
                placeholder="Kode Kota..."
                name="departureCityCode"
                id="departureCityCode"
                required
              />
            </div>
          </div>
          <div className="grid grid-cols-3 gap-4">
            <div className="space-y-2">
              <Label htmlFor="destinationCity">Kota Tujuan</Label>
              <Input
                placeholder="Kota Tujuan..."
                name="destinationCity"
                id="destinationCity"
                required
              />
            </div>
            <div className="space-y-2">
              <Label htmlFor="arrivalDate">Tanggal Tiba</Label>
              <Input
                type='datetime-local'
                placeholder="Tanggal Tiba..."
                name="arrivalDate"
                id="arrivalDate"
                className='block'
                required
              />
            </div>
            <div className="space-y-2">
              <Label htmlFor="destinationCityCode">Kode Kota</Label>
              <Input
                placeholder="Kode Kota..."
                name="destinationCityCode"
                id="destinationCityCode"
                required
              />
            </div>
          </div>
    
          <SubmitButtonForm />
        </form>
      )
    }