befabry
befabry

Reputation: 802

React Final Form Dynamic Dropdown with Prime React

I am trying to initialize a dynamic list of User with a DropDown from the PrimeReact library. I am able to load it, even though I am not sure if it is the right way. I am able to select a User, but unable to pass it down to the form. I am also not sure I am supposed to select the User without a state. I am a bit confused on how those interact between each other. It would be really helpful if I could have a bit of guidance.

import { useState, useEffect, useContext } from 'react'
import { Form, Field } from 'react-final-form'
import { Panel } from 'primereact/panel'
import { Dropdown, DropdownProps } from 'primereact/dropdown'
import { Button } from 'primereact/button'

import { api } from '../services' //Axios instance

export interface IUser {
    id: number
    firstName: string
    lastName: string
  }

const selectedUserItemTemplate = (option: IUser) => {
  return <span>{`${option.lastName} ${option.firstName}`}</span>
}

const selectedUserValueTemplate = (
  option: IUser,
  { placeholder }: DropdownProps
) => {
  return option ? (
    <span>{`${option.lastName} ${option.firstName}`}</span>
  ) : (
    <span>{placeholder}</span>
  )
}

const DropDownAdaptater = ({ input, meta, hintText, data, ...rest }: any) => {
  const [selectedUser, setSelectedUser] = useState(undefined)
  const [users, setUsers] = useState<IUser[]>([])
  useEffect(() => {
    const fetchUsers = async () => {
      const { data } = await api.get<IUser[]>('/users')
      setUsers(data)
    }
    fetchUsers()
  }, [])

  console.log(input.value) //Empty -> the form does not update

  return (
    <Dropdown
      {...input}
      value={selectedUser}
      options={users}
      onChange={(e) => setSelectedUser(e.target.value)}
      itemTemplate={selectedUserItemTemplate}
      valueTemplate={selectedUserValueTemplate}
      optionLabel="optionLabel"
      placeholder={hintText}
      style={{ marginRight: '1rem', width: '240px' }}
    />
  )
}

export const Login: React.FC = () => {
  const onSubmitAuthForm = () => {
    console.log('submit')
  }

  return (
    <Panel header="Login">
      <Form onSubmit={onSubmitAuthForm}>
        {({ handleSubmit, form, submitting, pristine, values }) => {
          console.log('values FORM', values) // -----> Empty
          return (
            <form onSubmit={handleSubmit}>
              <h5>Select a user</h5>
              <Field
                name="userName"
                component={DropDownAdaptater}
                hintText="Select a user"
              />
              <Button label="Login" />
            </form>
          )
        }}
      </Form>
    </Panel>
  )
}

Upvotes: 0

Views: 1709

Answers (1)

Alen.Toma
Alen.Toma

Reputation: 4870

Try updating the value your self.

See here is an example for the same

const DropDownAdaptater = ({ input, meta, hintText, data, ...rest }: any) => {
  const [selectedUser, setSelectedUser] = useState(undefined)
  const [users, setUsers] = useState<IUser[]>([])
  useEffect(() => {
    const fetchUsers = async () => {
      const { data } = await api.get<IUser[]>('/users')
      setUsers(data)
    }
    fetchUsers()
  }, [])

  useEffect(()=>{
      // update the input value, when selected
      // note: it must be a single value and not an object
      input.value= selectedUser.userName; 
  },[selectedUser])

  return (
    <Dropdown
      {...input}
      value={selectedUser}
      options={users}
      onChange={(e) => setSelectedUser(e.target.value)}
      itemTemplate={selectedUserItemTemplate}
      valueTemplate={selectedUserValueTemplate}
      optionLabel="optionLabel"
      placeholder={hintText}
      style={{ marginRight: '1rem', width: '240px' }}
    />
  )
}

Upvotes: 1

Related Questions