#dependent select dropdowns

20 messages · Page 1 of 1 (latest)

icy oak
#

I have a requirement where I need one form dropdown to trigger the options in another based on the selection. The common general use case for this would be the example of three dropdowns about location. The first is often the 'city', the second 'town' and the third would be the 'suburb'. Obviously the child options are not available until the parent has been selected.

I use this pattern in react-hook-form and I now have it working with tanstack form, but I'm using listeners to achieve this. But it doesn't seem quite right.
I was wondering if anyone has had any experience with this for tanstack form?

This is the concept I have so far:

//the parent select
<form.AppField
          listeners={{
            onChange: ({ value }) => {
              const subjects = subjectTree?.child?.find(subject => subject.code === value)
              const children = subjects?.child
              const options = children?.map(child => ({
                label: child.name,
                value: child.code,
              }))
              setSubjectOptions(options ?? []) 
            },
          }}
          children={field => (
            <field.SelectField
              selectItems={subfields}
            />
          )}
        />

//the dependent select
<form.AppField
          name='subject'
          children={field => (
            <field.SelectField
              selectItems={subjectOptions}
            />
          )}
        />

supple jolt
#

You'll probably need to add onChangeListenTo as well
https://tanstack.com/form/latest/docs/framework/react/guides/linked-fields

And you should take care that your depended fields get reset when the field they depend on changes (if I change the town, the suburb needs to reset)

You may find yourself needing to link two fields together; when one is validated as another field's value has changed. One such usage is when you have both a password and confirmpassword field, where...

#

👆 this might help you, just paste it below your Selcts into your JSX and you can see the internals of your form (you'll want to watch the values of the form probably)

icy oak
#

Thanks heaps. And is passing/setting state inside the listeners and options good practice?

hoary scaffold
icy oak
#

Another option I tried was having an onchange that has a useEffect instead, and then the form.useStore to set the values

#
    state: { value },
    handleChange,
  } = useField({
    form,
    name: 'city',
  })

const setSuburb = form.useStore((s) => s.state.values.suburb)

  React.useEffect(() => {
    form.updateFieldValue('suburb', '')
  }, [value])```
#

But I prefered the listener

#

... after I read more of the docs. It's a bit light on examples as why I'm here. Not feeling fully confident about it (my code) so far

hoary scaffold
#

Here's my suggestion in case you run into it in the future:

// Scenario 1: External state needs to be calculated (suburb available options)
const city = useStore(form.store, state => state.values.city)

const availableSuburbs = useMemo(() => {
  // some calculation with city to determine suburbs
}, [city]) 

// Scenario 2: Form state dependent on other form state (suburb field value)
// Do what ksgn recommended
<form.Field 
  name="city" 
  listeners={{
    onChange: ({ fieldApi }) => {
      // reset suburb if city changes
      fieldApi.form.setFieldValue('suburb', null)
    }
  }} 
  children={() => <></>}
/>
supple jolt
hoary scaffold
#

yeah, it's pretty good

#

also a good example of external dependent state since that's very common for js frameworks

icy oak
#

Yeah it took me a while to find the listener example and then play around inside. I understand the clean up stuff, I just left it out of my example (my bad)

#

In RFH I use the watch hook

hoary scaffold
#

Tanstack Form's useStore and RHF's watch are very similar in usage

icy oak
#

Out of curiosity, with your example, once the city has changed, then the available suburbs are calculated. how would I populate the available suburbs into the suburbs options? Is there an equivalent of resetting the default values of that field?

hoary scaffold
icy oak
#

Thanks guys, very helpful. I will get back to my use case tomorrow