hooks on { Select } from 'payload/components/forms'

default discord avatar
remy_90
9 months ago
4

I have the following DOM element select:


<select title="select" value={selectedOption} onChange={(e) => handleChange(e, path)}>
    {options.map((option, index) => <option value={option}>{option}</option>)}
  </select>


The above works as expected



I'm trying to use payload's Select, as referenced in the subject title. I imagine hooks is the way to manage state, as onChange isn't provided - but they aren't ever triggered?



<Select name='select' label="my select" options={options} hooks={{
    afterChange: [() => console.log('afterChange')],
    beforeChange: [() => console.log('beforeChange')],
    afterRead: [() => console.log('afterRead')],
    beforeValidate: [() => console.log('beforeValidate')],
  }} />


Am I missing something? I would like to set a default value from

useFormFields

and update the selected value onChange (as achieved in the first example)

  • discord user avatar
    jarrod_not_jared
    Payload Team
    9 months ago

    AH!



    I linked the wrong import path in our last discussion. 1 min



    Ok so you will want to import the Select component like so

    import SelectInput from 'payload/dist/admin/components/forms/field-types/Select/Input';

    (see the component here:

    https://github.com/payloadcms/payload/blob/master/src/admin/components/forms/field-types/Select/Input.tsx

    )



    This will give you the styled component - so it looks and feels like other payload select components.



    What you need to do is implement similar functionality seen in this file in your custom Field component:

    https://github.com/payloadcms/payload/blob/master/src/admin/components/forms/field-types/Select/index.tsx

    You can see how that file imports the

    <SelectInput />

    which is the one you will import, all of the state management (getting and setting options for your custom select) will live in a file that then passes props (onChange, value, options, etc) down to the SelectInput component.



    I hope this makes sense and steers you in the right direction!!

  • default discord avatar
    remy_90
    6 months ago

    Hi @jarrod_not

    jared , I'm back! Following your recommendation above I have the following:
    <SelectInput
      path={p}
      name='l'
      label='logic'
      options={options.map(option => option...)}
      onChange={e => handlePrerequisiteChange(e, path)}
    />

    The above doesn't persist between refreshes.

    The following sometimes works when another field is updated:
    ``html <select title='prerequisite' value={selectedOption} onChange={e => handlePrerequisiteChange(e, path)} > {options.map((option, index) => ( <option key={r-${index}} value={${option.question}

    ${option.answer}

    }> {

    ${option.question}_${option.answer}

    } </option> ))} </select> ``` * I'm still using

    useFormFields

    , I can't see how to make use of

    useFields

    (without violating react hook laws). How could I update each dropdown with useFields? My implementation is below * Changing an option in my select won't trigger the clean/dirty flag for saving/publishing changes but sometimes persists when other fields change Hopefully the content below will help paint a picture of what I'm working with and why I chose

    useFormFields

    : ```typescript // fields param is from: // const { fields, dispatch } = useFormFields(([fields, dispatch]) => ({ fields, dispatch })) const generateOptions: (fields: any) => string[] = fields => { const numberOfPages = pageState.pages.value const questionCombination = [...Array(numberOfPages).keys()].flatMap(pageNo => getAnswerOptionsFromAnswerTypes( // checks if boolean/multiple choice, etc // assuming there is currently only one question and answer fields[

    pages.${pageNo}.content.questions.0.answerType.0.blockType

    ], ).map<ConditionalLogicOptions>(option => ({ question: fields[

    pages.${pageNo}.content.questions.0.text

    ].value, answer: fields[

    pages.${pageNo}.content.questions.0.answerType.0.${option}

    ]?.value || '', })), ) return questionCombination } ``` Here's a screenshot displaying the dropdown comprised of state from multiple fields. using

    useField

    for the

    selectedValue

    triggers the clean/dirty flag for saving a draft/publishing and reloading sends it back to its previous value, so it's still not persisting Progress! I've used

    useField

    instead of

    useState` to set the selectedOption. That sorts out my clean/dirty and the reload.



    The only remaining issue is converting my un-styled select to your SelectInput. My select HTML is still as above. I'm getting page ids coming through for the dropdown when I use the following:


    <SelectInput
      path={path}
      name='logic'
      label='logic'
      options={options.map((option) => ({</option>)
        label: option,
        value: option
      }))}
      onChange={e => handlePrerequisiteChange(e, path)}
    />
    Screenshot_2023-05-10_at_16.22.02.png
  • default discord avatar
    aaronksaunders
    last month

    i am heading down this journey now, do you have some source code you wouldnt mind sharing

  • default discord avatar
    remy_90
    last month

    Hey Aaron, I'm hoping to make this publicly available at some point soon, perhaps as a plugin? In the interim, it's currently baked into closed source code, will send a DM for the time being

Open the post
Continue the discussion in Discord
Like what we're doing?
Star us on GitHub!

Star

Connect with the Payload Community on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.