40

The example code in the react-bootstrap site shows the following. I need to drive the options using an array, but I'm having trouble finding examples that will compile.

<Input type="select" label="Multiple Select" multiple>
  <option value="select">select (multiple)</option>
  <option value="other">...</option>
</Input>
Pavindu
  • 2,684
  • 6
  • 44
  • 77
JohnL
  • 13,682
  • 4
  • 19
  • 23

9 Answers9

49

You can start with these two functions. The first will create your select options dynamically based on the props passed to the page. If they are mapped to the state then the select will recreate itself.

 createSelectItems() {
     let items = [];         
     for (let i = 0; i <= this.props.maxValue; i++) {             
          items.push(<option key={i} value={i}>{i}</option>);   
          //here I will be creating my options dynamically based on
          //what props are currently passed to the parent component
     }
     return items;
 }  

onDropdownSelected(e) {
    console.log("THE VAL", e.target.value);
    //here you will see the current selected value of the select input
}

Then you will have this block of code inside render. You will pass a function reference to the onChange prop and everytime onChange is called the selected object will bind with that function automatically. And instead of manually writing your options you will just call the createSelectItems() function which will build and return your options based on some constraints (which can change).

  <Input type="select" onChange={this.onDropdownSelected} label="Multiple Select" multiple>
       {this.createSelectItems()}
  </Input>
Theo
  • 1,165
  • 9
  • 14
  • Nice explaination @Theo, im having a feature request, on selecting any option(single value only), it should,append the value of the corresponding option in the above input box, and on if i start type ,the option should open.THanks in Advance? – Aashiq Mar 03 '21 at 06:32
24

My working example

this.countryData = [
    { value: 'USA', name: 'USA' },
    { value: 'CANADA', name: 'CANADA' }            
];

<select name="country" value={this.state.data.country}>
    {this.countryData.map((e, key) => {
        return <option key={key} value={e.value}>{e.name}</option>;
    })}
</select>
dev-siberia
  • 2,746
  • 2
  • 21
  • 17
  • 3
    I think it would be more correct to omit the `key` (which I think is the array index), and instead set ` – Nathan May 06 '18 at 04:16
  • @Nathan - correct. This article goes into more detail...https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318 – John Livermore Jun 19 '18 at 21:11
7

bind dynamic drop using arrow function.

class BindDropDown extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      values: [
        { name: 'One', id: 1 },
        { name: 'Two', id: 2 },
        { name: 'Three', id: 3 },
        { name: 'four', id: 4 }
      ]
    };
  }
  render() {
    let optionTemplate = this.state.values.map(v => (
      <option value={v.id}>{v.name}</option>
    ));

    return (
      <label>
        Pick your favorite Number:
        <select value={this.state.value} onChange={this.handleChange}>
          {optionTemplate}
        </select>
      </label>
    );
  }
}

ReactDOM.render(
  <BindDropDown />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root">
    <!-- This element's contents will be replaced with your component. -->
</div>
Gabriel Bleu
  • 9,703
  • 2
  • 30
  • 43
Awais Asghar
  • 149
  • 1
  • 5
6
// on component load, load this list of values
// or we can get this details from api call also    
const animalsList = [
{
    id: 1,
    value: 'Tiger'
}, {
    id: 2,
    value: 'Lion'
}, {
    id: 3,
    value: 'Dog'
}, {
    id: 4,
    value: 'Cat'
}
];

// generage select dropdown option list dynamically
function Options({ options }) {
    return (
        options.map(option => 
                    <option key={option.id} value={option.value}>                                   
                    {option.value}
                    </option>)
                   );
}

<select
name="animal"
className="form-control">
<Options options={animalsList} />
</select>
3

Basically all you need to do, is to map array. This will return a list of <option> elements, which you can place inside form to render.

array.map((element, index) => <option key={index}>{element}</option>)

Complete function component, that renders <option>s from array saved in component's state. Multiple property let's you CTRL-click many elements to select. Remove it, if you want dropdown menu.

import React, { useState } from "react";

const ExampleComponent = () => {
    const [options, setOptions] = useState(["option 1", "option 2", "option 3"]);

    return (
        <form>
            <select multiple>
            { options.map((element, index) => <option key={index}>{element}</option>) }
            </select>
            <button>Add</button>
        </form>
    );
}

component with multiple select

Working example: https://codesandbox.io/s/blue-moon-rt6k6?file=/src/App.js

Human programmer
  • 408
  • 4
  • 11
2

A 1 liner would be:

import * as YourTypes from 'Constants/YourTypes';
....
<Input ...>
    {Object.keys(YourTypes).map((t,i) => <option key={i} value={t}>{t}</option>)}
</Input>

Assuming you store the list constants in a separate file (and you should, unless they're downloaded from a web service):

# YourTypes.js
export const MY_TYPE_1="My Type 1"
....
Jjang
  • 11,250
  • 11
  • 51
  • 87
2

You need to add key for mapping otherwise it throws warning because each props should have a unique key. Code revised below:

let optionTemplate = this.state.values.map(
    (v, index) => (<option key={index} value={v.id}>{v.name}</option>)
);
bdkopen
  • 494
  • 1
  • 6
  • 16
1

You can create dynamic select options by map()

Example code

return (
    <select className="form-control"
            value={this.state.value}
            onChange={event => this.setState({selectedMsgTemplate: event.target.value})}>
        {
            templates.map(msgTemplate => {
                return (
                    <option key={msgTemplate.id} value={msgTemplate.text}>
                        Select one...
                    </option>
                )
            })
        }
    </select>
)
  </label>
);
Rizwan
  • 3,741
  • 2
  • 25
  • 22
0

I was able to do this using Typeahead. It looks bit lengthy for a simple scenario but I'm posting this as it will be helpful for someone.

First I have created a component so that it is reusable.

interface DynamicSelectProps {
    readonly id: string
    readonly options: any[]
    readonly defaultValue: string | null
    readonly disabled: boolean
    onSelectItem(item: any): any
    children?:React.ReactNode
}

export default function DynamicSelect({id, options, defaultValue, onSelectItem, disabled}: DynamicSelectProps) {

    const [selection, setSelection] = useState<any[]>([]);

    return <>
        <Typeahead
            labelKey={option => `${option.key}`}
            id={id}
            onChange={selected => {
                setSelection(selected)
                onSelectItem(selected)
            }}
            options={options}
            defaultInputValue={defaultValue || ""}
            placeholder="Search"
            selected={selection}
            disabled={disabled}
        />
    </>
}

Callback function

function onSelection(selection: any) {
    console.log(selection)
    //handle selection
}

Usage

<div className="form-group">
    <DynamicSelect
        options={array.map(item => <option key={item} value={item}>{item}</option>)}
        id="search-typeahead"
        defaultValue={<default-value>}
        disabled={false}
        onSelectItem={onSelection}>
    </DynamicSelect>
</div>
Ruchira Nawarathna
  • 1,137
  • 17
  • 30