reack-hook-form selected dropdown value using reset

Viewed 344

I am working on updating details on the form of update location. I need to display the existing values in the form fields.

Here below is code of update component:

import axios from 'axios'
import { useState, useEffect } from 'react'
import { useForm } from 'react-hook-form'

export default function Edit({...props}) {
  const {
    register,
    handleSubmit,
    setValue,
    reset,
    formState: { errors },
  } = useForm({mode: 'onBlur' });

   useEffect(() => {
    
    if (props.locationDetails) {
        console.log(props.locationDetails) 
        // in this console I can get { 'name' : 'name value',  'company' : 'UUID'}
        reset( props.locationDetails);
    }
   }, [reset])

   const editLocation = async(data) => {
       .....
   }

   return (
     <form className="g-3" onSubmit={handleSubmit(editLocation)} data-testid="editLocationForm">

        <input type="text" {...register('name', { required: true })} className="form-control"  placeholder="Enter Name Here" />
                                                    {errors.name && <p className="error" role="error" >Name is required.</p>}

        <select {...register('company', { required: true })} 
                className="form-control" >
                {props.companies && props.companies.map((company, index) => {
                <option key={index} value={company.UUID}>{company.name}</option>
                }
                )}
        </select>
       
        .....
     </form>
   )

}



   export async function getServerSideProps({ params }) {

    if(params.id) {
        let locationId = params.id

        let locationResponse = await axios(process.env.BASE_URL + '/locations/' + locationId,{
            headers : {
                'Content-Type': 'application/json',
                'Authorization' : 'Bearer ' + process.env.TOKEN
            }
        })

        let companiesResponse = await axios(process.env.BASE_URL + '/companies',{
            headers : {
                'Content-Type': 'application/json',
                'Authorization' : 'Bearer ' + process.env.TOKEN
            }
        })

        if(locationResponse.status == 200 && locationResponse.data && companiesResponse.status == 200) {
            
            let locationDetails = await locationResponse.data

            let companies = await companiesResponse.data.results

            locationDetails.company = locationDetails.links.Company

            return {
                props : {
                    locationDetails: locationDetails,
                    companies: companies
                }
            }
        } else {
            return {
                props : {
                    locationDetails: {},
                    locationDetails:{}
                }
            }
        }    
    } else {
        return {
            props : {
                locationDetails: {},
                locationDetails:{}
            }
        }

    }
}

Here I am able to set all existing values of location in their input text fields but unable to display selected dropdown.

response structure is as follows:

{
   "name": "New York",
   "country": "USA",
   "company": "UUID"   <<<< this is the uuid which needs to be selected on select dropdown.
}
3 Answers

For nested field, add the dot between the properties:

<select {...register("links.company", { required: true })}>
  {(companies || []).map((company, index) => (
    <option key={index} value={company.UUID}>
      {company.name}
    </option>
  ))}
</select>

Codesandbox Demo

Like written previously you need to return some jsx

<select onChange={onChange}>
  {(companies || []).map((companyData, index) => (
    <option key={index} value={companyData.links.UUID}>
      {company.name}
    </option>
  ))}
</select>

This will return the nested value.

if you need to manage the state by react


const [selectedData, setSelectedData] = useState("");

const onChange = useCallback((event)=>{
   const valueReturned = evant.target.value;
   setSelectedData(valueReturned)
   ... do what you need
}, [... put here dependencies])

...

<select onChange={onChange} value={selectedData}>
  {(companies || []).map((companyData, index) => (
    <option key={index} value={companyData.links.UUID}>
      {company.name}
    </option>
  ))}
</select>

here it is an example of a callback that will manage the state as controlled component

https://reactjs.org/docs/forms.html#controlled-components

if you want you can use also uncontrolled components

https://reactjs.org/docs/uncontrolled-components.html

To remove the nesting issue, I modified the response in serversideprops as

locationDetails.company = locationDetails.links.Company

this I have also updated in question earlier.

Here is the code which I have used to show the existing option as selected.

<select {...register('company', { required: true })} className="form-control">
   {(props.companies || []).map((company, index) => (
   <option key={index} value={company.UUID} selected={company.UUID === register.company}>
           {company.name}
   </option>
))}

selected={company.UUID === register.company} is the condition.

Related