Home > front end >  Map through array of objects
Map through array of objects

Time:06-23

I was wonder what I'm doing wrong here. I map through categories and it works perfect. But when I map through sub-categories in dropdown it shows not parent sub-categories, but all items from all categories. For example if I choose category "Developer" in sub categories drop-down I want to show only Front-end, Back-End and Full-Stack options.

setCategory comes from props and the state looks like this:

const [category, setCategory] = useState("");

Code: belox:

<div className="inner--form--row">
    <label htmlFor="category">Category:</label>
    <select id="category" onChange={(e) => setCategory(e.target.value)}>
      <option defaultValue={true}>Choose...</option>
      {categories.map((category) => (
        <option value={category.label} key={category.id}>
          {category.label}
        </option>
      ))}
    </select>
  </div>
  <div className="inner--form--row">
    <label htmlFor="subCategory">Sub Category:</label>

    <select id="category" onChange={(e) => setSubCategory(e.target.value)}>
      <option defaultValue={true}>Choose...</option>
      {categories.map((category) => (
        <>
          {category.subCategories.map((subCat) => (
            <option value={subCat.label} key={subCat.id}>
              {subCat.label}
            </option>
          ))}
        </>
      ))}
    </select>
  </div>

enter image description here

Data looks like this:

categories: [
    {
      id: 1,
      label: "Developer",
      subCategories: [
        {
          id: 2,
          label: "Front-End Developer",
          subCategories: [
            {
              id: 3,
              label: "Junior",
            },
            { id: 4, label: "Mid" },
            {
              id: 5,
              label: "Senior",
            },
          ],
        },
        {
          id: 6,
          label: "Back-End Developer",
          subCategories: [
            { id: 7, label: "Junior" },
            { id: 8, label: "Mid" },
            { id: 9, label: "Senior" },
          ],
        },
        {
          id: 10,
          label: "Full-Stack Developer",
          subCategories: [
            { id: 11, label: "Junior" },
            {
              id: 12,
              label: "Mid",
            },
            {
              id: 13,
              label: "Senior",
            },
          ],
        },
      ],
    },
    ....

CodePudding user response:

I have explained the changes on the comments

const [category, setCategory] = useState("");

const handleSetCategory = () => {
  const categoryId = e.target.value;
// here find the category by Id so that you can map through it
  const category = categories.find(cat => cat.id === categoryId); 
  setCategory(category);
}

<div className="inner--form--row">
    <label htmlFor="category">Category:</label>
    <select id="category" onChange={(e) => handleSetCategory(e)}> // Here call handle function
      <option defaultValue={true}>Choose...</option>
      {categories.map((category) => (
        <option value={category.id} key={category.id}> // Here set value as id
          {category.label}
        </option>
      ))}
    </select>
  </div>
  <div className="inner--form--row">
    <label htmlFor="subCategory">Sub Category:</label>

    <select id="category" onChange={(e) => setSubCategory(e.target.value)}>
      <option defaultValue={true}>Choose...</option>
  // here map from category that was set :)
      {category.subCategories.map((subCat) => (
    <option value={subCat.label} key={subCat.id}>
      {subCat.label}
    </option>
  ))}
    </select>
  </div>

CodePudding user response:

I think that the problem is at this part of the code:

<select id="category" onChange={(e) => setCategory(e.target.value)}>
  <option defaultValue={true}>Choose...</option>
  {categories.map((category) => (
    <>
      {category.subCategories.map((subCat) => (
        <option value={subCat.label} key={subCat.id}>
          {subCat.label}
        </option>
      ))}
    </>
  ))}
</select>

Maybe what you meant to do is this:

<select id="category" onChange={(e) => setCategory(e.target.value)}>
  <option defaultValue={true}>Choose...</option>
  {category.subCategories.map((subCat) => (
    <option value={subCat.label} key={subCat.id}>
      {subCat.label}
    </option>
  ))}
</select>

The way you did you are basically mapping all subcategories to the options indeed, because you going through all categories and then mapping all of its subcategories as options. You already know which is the selected category, so you don't need to loop through all categories again.

  • Related