Search code examples
javascriptreactjstypescriptdrop-down-menuselect-options

How to obtain additional data from select options choice in React / Typescript app


I have an array of exchanges, once the user selects an exchange, I want to use both the exchange's name and its base quote.

For example, if the user selects the first option below, I want to capture "poloniex" as well as the base key "USDC".

enter image description here

First I tried using this:

{exchanges.map((exchange, i) =>
  (<option key={i} value={exchange.exchange} base={exchange.quote}>
    {capFirst(exchange.exchange)} ({exchange.quote}) ${exchange.price_quote}
  </option>))}

However I get the error that base does not exist, however shouldn't I be able to add any attribute to an option? Perhaps not if it's in JSX? Also data didn't work.

Type '{ children: string[]; key: number; value: string; base: string; }' is not assignable to type 'DetailedHTMLProps, HTMLOptionElement>'. Property 'base' does not exist on type 'DetailedHTMLProps, HTMLOptionElement>'.ts(2322)

Another way I tried is to get the index key of the option selected, however the follow code produces key = null.

Below target.value will give me its value, but I also need the base quote.

@bind
handleExchangeSelect(event: React.FormEvent<HTMLSelectElement>) {
  const { exchanges } = this.props;
  const target = event.target as HTMLSelectElement;
  console.log('target', target);
  const exchange = target.value;
  const key = target.getAttribute('key');
  console.log('exchange', exchange);
  console.log('key', key);
  // if (key) {
  //   console.log(exchanges[Number(key)]);
  // }
  this.setState({
    exchange,
    // exchange_base: base ? base : ''
  });
}

Solution

  • The react way to solve that would be to create an own select component which could look like this:

    class ExchangeSelect extends Component {
        handleSelect = event => {
            const {exchanges, onSelect} = this.props;
            const selected = exchanges.find(exchange => exchange.exchange === event.target.value);
            onSelect(selected);
        };
    
        render() {
            const {exchanges} = this.props;
    
            return (
                <select onChange={this.handleSelect}>
                    {exchanges.map(exchange => (
                        <option key={exchange.exchange} value={exchange.exchange}>
                            {exchange.exchange} ({exchange.quote}) ${exchange.price_quote}
                        </option>
                    ))}
                </select>
            );
        }
    }
    

    With exchanges being a list of exchange objects you could then use it like this:

    const exchanges = [
        {exchange: 'poloniex', quote: 'USDC', price_quote: '0.42'},
        {exchange: 'bitibu', quote: 'USDT', price_quote: '0.666'},
        {exchange: 'bittrex', quote: 'USDT', price_quote: '0.21'},
    ];
    

    In render():

    <ExchangeSelect 
        exchanges={exchanges} 
        onSelect={exchange => console.log(exchange.quote)} 
    />
    

    Live Example:

    Edit 2z23n1n26n