简体   繁体   中英

When selecting an option in a dropdown, how do I change the state with onChange but with a value other than the one inside the option tags

Need some help with dropdowns. I can't seem to figure out a way to pass in the ID specific to that particular dropdown <option> so that when the user makes a selection that value can be used (for example to setState ). The usual case is to read the value of the dropdown itself, but in my case I don't want the displayed value but another value that is 'behind the scenes' or hidden.

Please note I've already researched about controlled components in react for forms etc, this issue is a bit different and my attempts to find an answer have come up empty.

I'm using react and javascript but I think if you know a little about javascript you may be able to help.

The dropdowns are set up like shown below where on changing the dropdown selection it runs the function handleStatusChange .

<select
   id="inputIdentity"
   className="select-form"
   onChange={this.handleStatusChange}
 >
    <option value="" hidden>
       please choose
    </option>

    <option>status1</option>
    <option>status2</option>
    <option>status3</option>
</select>

In actual practice the options are mapped out from data fetched via an api as they can be altered in the backend:

<select
  id="inputIdentity"
  className="form-control content-input"
  onChange={this.handleStatusChange}
>
  <option value="" hidden>
    Please Choose
  </option>
     {statusData ? (
        statusData.map((status) => (
            <option>{status.title}</option>
        ))
      ) : (
        <option>Loading...</option>
      )}
</select>

this.handleStatusChange checks the value of the event (which is the act of changing the selection in the dropdown, the value is accessed with: e.target.value ) to read the value inside the <option> that was chosen... The method for reading the chosen dropdown value is something like:

handleStatusChange = (e) => {
   this.setState({
      // set it to state
      status: e.target.value
   });
  };
I

This is the standard way to do it.

Now we get back to the question - is there a way to read a value from each dropdown that is NOT shown (read from e.target.value) instead, ie. if they each had an ID or something, how do I pass that in so that e.target.value would be able to access this id.

If you take a look at the version where I map out (or loop out if you aren't familiar with the map function) the <option> tags and in each iteration I pass in the title with {status.title} . I can access the id with status.id but the onChange handler is in the <select> tag and can't be within the map / loop, so to handle it by passing in the id into the onChange handler is not possible either.

What would be the correct way for the onChange handler to have access to that specific value which is not displayed between <option> tags?

You can keep the options in your component state and use the array method find to find the option that corresponds to the selected option and use that.

Example

 class App extends React.Component { state = { options: [ { value: "status1", label: "Status 1", secretValue: "foo" }, { value: "status2", label: "Status 2", secretValue: "bar" }, { value: "status3", label: "Status 3", secretValue: "baz" } ], selectedOption: "" }; handleStatusChange = e => { const { value } = e.target; this.setState(prevState => { const { secretValue } = prevState.options.find( option => option.value === value ); console.log(secretValue); return { selectedOption: value }; }); }; render() { const { options, selectedOption } = this.state; return ( <select value={selectedOption} onChange={this.handleStatusChange}> <option value="" hidden> please choose </option> {options.map(option => ( <option key={option.value} value={option.value}> {option.label} </option> ))} </select> ); } } ReactDOM.render(<App />, document.getElementById("root")); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div> 

is there a way to read a value from each dropdown that is NOT shown (read from e.target.value) instead, ie. if they each had an ID or something, how do I pass that in so that e.target.value would be able to access this id.

e.target is a reference to the HTMLSelectElement where the change occurred. You can find the option with the matching value in its options list, and then use that HTMLOptionElement 's properties, like this:

handleStatusChange({target}) {
    const value = target.value;
    const optionElement = Array.from(target.options).find(opt => opt.value === value);
    // If found, use information from `optionElement` to find the
    // entry in `statusData` in a state change, e.g.:
    if (optionElement) {
        const id = optionElement && optionElement.id;
        if (id) {
            this.setState(state => {
                const entry = state.statusData.find(e => e.id === id);
                if (entry) {
                    // Use `entry`'s information
                }
            }
        }
    }
}

React example, using a details property on the entries in statusData :

 class Example extends React.Component { constructor(...args) { super(...args); this.handleStatusChange = this.handleStatusChange.bind(this); this.state = { detail: "", statusData: [ {id: "one", title: "One", detail: "Details for one"}, {id: "two", title: "Two", detail: "Details for two"}, {id: "three", title: "Three", detail: "Details for three"} ] }; } handleStatusChange({target}) { const value = target.value; const optionElement = Array.from(target.options).find(opt => opt.value === value); const id = optionElement && optionElement.id; if (id) { this.setState(state => { const entry = state.statusData.find(e => e.id === id); if (entry) { return { detail: entry.detail } } }); } } render() { const {statusData, detail} = this.state; return ( <div> <select id="inputIdentity" className="form-control content-input" onChange={this.handleStatusChange} > <option value="" hidden> Please Choose </option> {statusData ? ( statusData.map((status) => ( <option id={status.id}>{status.title}</option> )) ) : ( <option>Loading...</option> )} </select> <div>Detail: {detail}</div> </div> ); } } ReactDOM.render( <Example />, document.getElementById("root") ); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div> 

you can pass that value to the loop showing the Options.

{statusData ? (
    statusData.map((status) => (
        <option value={status.value}>{status.title}</option>
    ))
  ) : (
    <option>Loading...</option>
  )}

and in order to do that you have to modify your array statusData .

hiddenData = ['a', 'b', 'c'];
statusData.map((s, index) => {
    s.value = hiddenData[index]
    return s;
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM