John
John

Reputation: 336

How to create dynamic drop down using formik in react?

I am receiving this json Response From API.

{
    "1": "Suits",
    "2": "Sarees",
    "3": "Footmats",
    "4": "Carpets",
    "5": "Sofa Covers"
}

I want to take this json and display it in a drop down using formik

// Setting State
state = {
        itemType: {
            key: 0,
            value: 'Select'
        }
}

// Calling API in component did mount
componentDidMount() {
    axios.get('/itemTypes')
        .then(response => {
            this.setState({
                itemType: response.data
            });
            this.createItemType();
        }).catch(error => {
            console.log(error);
        });
}

// filling options values for drop down
createItemType = () => {
    let items = [];
    for (const [key, value] of Object.entries(this.state.itemType)) {
        items.push(<option key={key} value={key}>{value}</option>);
        //here I will be creating my options dynamically
    }
    return items;
}

// I have this field component to create drop down in <Formik> <Form> tag.
<Field name="itemType" className="form-control" component="select" placeholder="Item Type">
    {this.createItemType}
</Field>

My aim is to create dynamic values drop down like this

enter image description here

What I am getting on screen is enter image description here

No drop down, only values gets printed.

Any help will be appriciated

Upvotes: 3

Views: 4648

Answers (1)

Zsolt Meszaros
Zsolt Meszaros

Reputation: 23160

You receive the error message because your Field component is an input field by default which can't have children. If you want it to be a select element, you can use the as prop:

<Field
  className="form-control"
  as="select"
  onChange={this.onItemTypeDropdownSelected}
  name="itemType"
>
  <option>...</option>
</Field>

You mentioned in a comment that it's not really necessary to use Map, the only reason you wanted that is because you're coming from Java. If your keys are strings (as in your example), you can use plain objects instead of Map. If you want to use Map however, you can convert a JSON object like this for example:

function objToMap(obj) {
  let map = new Map();

  for (let [key, value] of Object.entries(obj)) {
    map.set(key, value);
  }

  return map;
}

Edit: As you're no longer using Map, I've updated the snippet below:

state = {
  itemTypes: {},
};

componentDidMount() {
  axios
    .get('/itemTypes')
    .then((response) => {
      this.setState({
        itemTypes: response.data,
      });
      // you don't use this.createItemType() here 
      // just iterate over the state.itemTypes in render
    })
    .catch((error) => {
      console.log(error);
    });
};

render() {
  const options = [];
  for (let [key, value] of Object.entries(this.state.itemTypes)) {
    options.push(
      <option key={key} value={key}>
        {value}
      </option>
    );
  }

  return (
    <Field
      className="form-control"
      as="select"
      onChange={this.onItemTypeDropdownSelected}
      name="itemType"
    >
     {options}
    </Field>
  }

Upvotes: 4

Related Questions