1

so I have the following component that is a dropdown list created using react-select.

import React from 'react'
import Select from 'react-select';

const options = [
  { value: 'chocolate', label: 'Chocolate' },
  { value: 'strawberry', label: 'Strawberry' },
  { value: 'vanilla', label: 'Vanilla' }
];


class MealsFilters extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedOption: null,
    };
  }

  handleChange = (selectedOption) => {
    this.setState({ selectedOption });
    console.log(`Option selected:`, selectedOption);
  }

  render() {
    const { selectedOption } = this.state;
    return (
      <div className="container my-3">
        <div className="row">
          <div className="col-lg-4 col-md-6 col-sm-8">
            <Select
            isMulti
            isSearchable
            placeholder={"catégories"}
            value={selectedOption}
            onChange={this.handleChange}
            options={options}
            />
          </div>
        </div>
      </div>
    )
  }
}

export default MealsFilters;

the options variable is the default one from the docs. I actually need to replace its values by each meal category available. To do so, as you can see, I need to create an array of objects with a value and a label.

this component accesses meal categories through props called meals that are like so:

console.log(this.props.meals);

=> [{
     id: 0,
     name: spaghettis,
     category: italian,
     price: 5.99},
    {
     id: 1,
     name: hamburger,
     category: american,
     price: 7.99},
     {
      etc.
      }, {}]

How can I take advantage of this.props.meals to get my options array of objects ?

EDIT: multiple meals can have the same category, and I need each category to only appear once in the options.

4 Answers 4

2

Map over your this.props.meals array, and create the needed options array,

<Select
    isMulti
    isSearchable
    placeholder={"catégories"}
    value={selectedOption}
    onChange={this.handleChange}
    options={this.props.meal.map(item=>({value: item.id, label: item.name}))}
/>
Sign up to request clarification or add additional context in comments.

1 Comment

thank you very much for your help ! please see my post edit, I'd like to find a way to have each category (I'm not looking for name btw) to appear only once in the options.
1

You could do something like this:

options={this.props.meals.map(
  ({id, name})=>({value:id,label:name})
)}

You could also use redux connect to create a container that will map the data to dropdown values for you

You can merge the data by category in the following way:

var items = [
  {
    id: 0,
    name: 'spaghettis',
    category: 'italian',
    price: 5.99,
  },
  {
    id: 1,
    name: 'hamburger',
    category: 'american',
    price: 7.99,
  },
  {
    id: 2,
    name: 'other hamburger',
    category: 'american',
    price: 7.99,
  },
];

console.log(
  [
    ...items.reduce(
      (result, item) => (
        result.get(item.category)
          ? result.get(item.category).push(item.id)
          : result.set(item.category, [item.id]),
        result
      ),
      new Map(),
    ),
  ].map(([label, value]) => ({ label, value })),
);

In the component it'll look like this:

options={[
  ...this.props.meals.reduce(
    (result, item) => (
      result.get(item.category)
        ? result.get(item.category).push(item.id)
        : result.set(item.category, [item.id]),
      result
    ),
    new Map(),
  ),
].map(([label, value]) => ({ label, value }))}

4 Comments

Thank you @HMR ! actually I forgot to mention that some meals have the same category. And I want to have each category only once in the options. I'll edit my post right now to make it clearer.
@JulesCorb Would you throw out the items that have the same category as a previous one or would you merge these items. If you want to merge then how would you merge the items? Probably best to provide a sample source and expected output.
Both solutions would suit to my problem. All I need is to have each category only once in my options. So it doesn't mater whether I have to throw out or merge items. I'll go for the simplest, most DRY solution.
@JulesCorb Updated the answer.
1

You only need the "name" property so when you map through meals, simply retrieve it. Then upper case the first letter.

const meals = [{
    id: 0,
    name: "spaghettis",
    category: "italian",
    price: 5.99
  },
  {
    id: 1,
    name: "hamburger",
    category: "american",
    price: 7.99
  }
]

const result = meals.map(({name}) => ({
  label: `${name[0].toUpperCase()}${name.slice(1)}`,
  value: name
}))

console.log(result);

Comments

1

You can use getOptionLabel and getOptionValue props.

<Select
    options={this.props.meals},
    getOptionLabel={m => m.name}
    getOptionValue={m => m.id} />

https://react-select.com/props

getOptionLabel generic = (option) => string

Resolves option data to a string to be displayed as the label by components

getOptionValue generic = (option) => string

Resolves option data to a string to compare options and specify value attributes

1 Comment

as said in my post I actually need the category and not the name. isn't it getOptionLabel={(m) => m.name} rather than getOptionLabel={(m) => c.name} ? anyway apart from those details this is a valid answer too, so thank you very much ! The thing is, I need each category only once, and this gives me the same category multiple times in the options.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.