walker1
walker1

Reputation: 361

Passing a function to select html in React

I mapping over data which displays different select option dropdowns. I need my onChange function to be on the select tag to capture the selected option, but the select tag is before the function is initialized so I'm not sure how to go about passing the function into it.

                <select onChange={onChange}>  <--- onChange function cant be passed  here
                    {options.map((attribute) => {
                        function onChange(event) {
                            const newSelected = { ...selected };
                           newSelected[attribute.title] = event.target.value
                        }

                        return (
                            <option value={attribute.index}>{attribute.value}</option>
                        )
                    })}
                </select>

Upvotes: 0

Views: 68

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074495

Define your onChange so that it uses the information on the event object it receives to find the right entry in the list, something like this:

<select onChange={event => {
    const attribute = options[event.currentTarget.value];
    const newSelected = {
        ...selected,
        [attribute.title]: event.currentTarget.value,
    };
    // ...
}}>
    {options.map((attribute, index) => {
        return (
            <option key={attribute.value} value={index}>{attribute.value}</option>
        )
    })}
</select>

It's hard to be sure the details of that are right without knowing the structure of options or what you want newSelected to be, but I think I've mostly inferred it from the question's code. Note that I changed attribute.index to index in the map call, and that I added a key (you need key on any array you render), assuming that attribute.value is unique.

That said, if attribute.value is unique, I think I'd use it instead of index or attribute.index:

<select onChange={event => {
    const attribute = options.find(({value}) => value == event.currentTarget.value);
    const newSelected = {
        ...selected,
        [attribute.title]: attribute.index,
    };
    // ...
}}>
    {options.map(({value}) => {
        return (
            <option key={value} value={value}>{value}</option>
        )
    })}
</select>

Upvotes: 1

TKoL
TKoL

Reputation: 13902

I think I sort of see why you're doing it the way you're doing it, so let me try to address how to handle it differently:

First of all, you're doing it because the onChange function needs access to the attribute.title value. So for you, you're thinking the easiest way to get that value is to define the function in the .map function, where you have access to each individual attribute as it's coming through.

You can't, though. As I said in my comment: It conceptually doesn't make sense. <select onChange={onChange}> implies a singular onChange function, but you're defining a new onChange function in every iteration of .map.

So what you need to do is define onChange before your render function, and then inside that you have to find the matching attribute inside the options array, so that you can then use attribute.title as you like.

[edit] TJ Crowder gives a specific code example of how to do that.

Upvotes: 1

Related Questions