user2953989
user2953989

Reputation: 3019

groupBy json data then map in React component

I'm trying to group my JSON data so that all staff in the same 'department' are in an object together. Then I want to map through the data so I can display it on my webpage.

At the moment i'm getting the error 'cannot read property of map undefined'

my JSON data:

people:[  
  {  
     id:"a0bef",
     title:"cleaner",
     department:"facilities",

  },
  {  
     id:"a0beg",
     title:"maintenance",
     department:"facilities",

  },
  {  
     id:"a0beh",
     title:"cleaner",
     department:"facilities",

  },
  {  
     id:"a0bei",
     title:"chef",
     department:"kitchen",

  },
  {  
     id:"a0bej",
     title:"waitress",
     department:"kitchen",

  }
]

which I would like to look like:

people:[  
  "facilities":[  
     {  
        id:"a0bef",
        title:"cleaner"
     },
     {  
        id:"a0beg",
        title:"maintenance"
     },
     {  
        id:"a0beh",
        title:"cleaner"
     }
  ],
  "kitchen":[  
     {  
        id:"a0bei",
        title:"chef"
     },
     {  
        id:"a0bej",
        title:"waitress"
     }
  ]
]

this is what I have tried:

import React from 'react'
import _ from 'lodash'

class PeopleList extends React.Component {
  constructor (props) {
    super(props)
  }

  render () {
    const { peoplelist } = this.props
    const people = _.groupBy(peoplelist, 'department')
    return (
      <div>
        { Object.people.map(function (person, key) {
          return (
            <div className='row' key={key}>
              <div className='col-md-6'>{person.department}</div>
              <div className='col-md-4'>{person.title}</div>
            </div>
          )
        }) }
      </div>
    )
  }
}



export default PeopleList

Upvotes: 0

Views: 3442

Answers (3)

jo_va
jo_va

Reputation: 13993

If you want to group your items by department and then display a list of persons ordered by department, then you need to map twice. Once over the departments, and then once over each person in each department.

To iterate over the departments, you will need to use Object.values() or Object.entries().

Here is an example using reduce() to implement groupBy:

const people = [
  { id: "a0bef", title: "cleaner", department: "facilities" },
  { id: "a0beg", title: "maintenance", department: "facilities" },
  { id: "a0beh", title: "cleaner", department: "facilities" },
  { id: "a0bei", title: "chef", department: "kitchen" },
  { id: "a0bej", title: "waitress", department: "kitchen" }
]

function groupBy(data, key) {
  return data.reduce((acc, x) => {
    acc[x[key]] = [...(acc[x[key]] || []), x];
    return acc;
  }, {});
}

class PeopleList extends React.Component {
  constructor(props) {
    super(props)
  }

  render() {
    const people = groupBy(this.props.people, 'department')
    return (
      <div className='container'>
        {Object.entries(people).map(([dep, staff]) => {
          return (
            <div className='dep' key={dep}>
              <span className='dep-name'>{dep}</span>
              {staff.map(person => {
                return (
                  <div className='row' key={person.id}>
                    <div className='col-xs-6'>Dep: {person.department}</div>
                    <div className='col-xs-4'>Title: {person.title}</div>
                  </div>
                )
              })}
            </div>
          )
        })}
      </div>
    )
  }
}

ReactDOM.render(
  <PeopleList people={people} />,
  document.getElementById('root')
);
.dep {
  border: 1px solid black;
  margin: 5px;
  padding: 5px;
}
.dep-name {
  font-weight: bold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<div id="root"></div>

Upvotes: 1

Sunil Chaudhary
Sunil Chaudhary

Reputation: 4743

You are getting this error because Object.people is not a valid syntax.

people after const people = _.groupBy(peoplelist, 'department') will be an Object. You need to get all the values of the object (using Object.values(people)); which will give you an array of person. Then, map through that array to get the desired output.

The function will be modified to

Object.values(people).map(function (deptArray) { 
    return deptArray.map(function (person) {
      return (
        <div className='row' key={some-unique-key}>
          <div className='col-md-6'>{person.department}</div>
          <div className='col-md-4'>{person.title}</div>
        </div>
      )            
    })
})

Note: In the above case you won't be able to use array indexes as the key, because the keys will be repeated (and so, I have removed it from my solution).

Hope it helps. Revert for any clarifications/doubts.

Upvotes: 1

Utsav Patel
Utsav Patel

Reputation: 2899

At the moment i'm getting the error 'cannot read property of map undefined'

This is due to this line in your return statement { Object.people.map(function (person, key)

const people = _.groupBy(peoplelist, 'department')

Above will you an object of 2 arrays i.e facilities and kitchen.

So you can do the following for displaying the data.

Object.values(people).map(dept => {
  dept.map((person, key) => {
    return (
      <div className='row' key={key}>
        <div className='col-md-6'>{person.department}</div>
        <div className='col-md-4'>{person.title}</div>
      </div>
    )
  })
})

Upvotes: 1

Related Questions