Patrick José
Patrick José

Reputation: 425

How to map over this specific json object

I have a json object that i can't find a way to map over it. I get it via my api in the backend.

My Json:

{
  "cn": [
    "Hermes Conrad"
  ], 
  "description": [
    "Human"
  ], 
  "mail": [
    "[email protected]"
  ], 
  "ou": [
    "Office Management"
  ], 
  "sn": [
    "Conrad"
  ], 
  "uid": [
    "hermes"
  ]
}

My component:

export default function UserDetails({ data }) {

  const classes = useStyles()


  return (

     <div className={classes.root} >
       <h1>User Details</h1>
       <Table className={classes.table} size="small">
         <TableHead>
           <TableRow>
             <TableCell align="left">cn</TableCell>
             <TableCell align="left">description</TableCell>
             <TableCell align="left">mail</TableCell>
             <TableCell align="left">ou</TableCell>
             <TableCell align="left">sn</TableCell>
             <TableCell align="left">uid</TableCell>
           </TableRow>
         </TableHead>
         <TableBody>
           {data.map(details => (
             <TableRow key={details.cn}>
               <TableCell component="th" scope="row"> </TableCell>
               <TableCell align="left">{details.cn}</TableCell>
               <TableCell align="left">{details.description}</TableCell>
               <TableCell align="left">{details.mail}</TableCell>
               <TableCell align="left">{details.ou}</TableCell>
               <TableCell align="left">{details.sn}</TableCell>
               <TableCell align="left">{details.uid}</TableCell>
             </TableRow>
           ))}
         </TableBody>
       </Table>
     </div>
   )
}

the data holds my json object, if i console log it i can see it, but if i just try out this code it does nothing.

Upvotes: 2

Views: 469

Answers (6)

pritam
pritam

Reputation: 2558

To start with just solving this problem, you can use Object.keys() to grad the keys as -

const keys = Object.keys(INPUT);
// You get an array of keys as return value

Loop over the keys and parse the response as key value pairs:

const getMappedData = () => {
    const keys = Object.keys(INPUT);
    const parsedOutput = {};
    keys.forEach(key => {
      const value = INPUT[key][0]; // considering the json you have
      parsedOutput[key] = value;
    })

    return parsedOutput;
  }

Then you'd have a details object of which you can read values like -

<TableCell align="left">{details.description}</TableCell>
<TableCell align="left">{details.mail}</TableCell>

Better solution

Consider the email property, if only one email is assigned to a customer, the API response should contain a key-value pair, where value is a type of string and is NOT an array.

So if you change the API implementation to respond with something like this -

{
    "cn":"Hermes Conrad", 
    "description": "Human",
    "mail":"[email protected]",
    "ou": "Office Management",
    "sn": "Conrad",
    "uid": "hermes"
}

So instead of grabbing the keys of INPUT, you could directly use the object as:

...
<TableCell align="left">{details.description}</TableCell>
<TableCell align="left">{details.mail}</TableCell>
...

You won't even have to use a mapper we used earlier.

IMP NOTE

Since you're doing -

 {data.map(details => ( ...

You're assuming this -

  1. Your data is an array. e.g. data contains -
[
{
  "cn": [
    "Hermes Conrad"
  ], 
  "description": [
    "Human"
  ], 
  "mail": [
    "[email protected]"
  ], 
  "ou": [
    "Office Management"
  ], 
  "sn": [
    "Conrad"
  ], 
  "uid": [
    "hermes"
  ]
},
{
  "cn": [
    "Hermes Conrad Jr."
  ], 
  "description": [
    "Human"
  ], 
  "mail": [
    "[email protected]"
  ], 
  "ou": [
    "Office Management"
  ], 
  "sn": [
    "Conrad2"
  ], 
  "uid": [
    "hermes2"
  ]
}
]
  1. You data always has some value. You should guard it by checking the length of data.
...
const hasData = data && data.length !== 0;
return (
    { hasData && data.map(details => ( ...
...

Sandbox for this is available here.

Upvotes: 1

MNN TNK
MNN TNK

Reputation: 372

to map this specific JSON :

{
  "cn": [
    "Hermes Conrad"
  ], 
  "description": [
    "Human"
  ], 
  "mail": [
    "[email protected]"
  ], 
  "ou": [
    "Office Management"
  ], 
  "sn": [
    "Conrad"
  ], 
  "uid": [
    "hermes"
  ]
}

First parse JSON

const data = JSON.parse(jsonObj);

And then map it like this :

<TableRow key={data['cn'][0]}>
<TableCell component="th" scope="row"> </TableCell>
{Object.keys(data).map(k => (
    <TableCell align="left">{data[k][0]}</TableCell>  
))}
</TableRow

>

Upvotes: 0

MNN TNK
MNN TNK

Reputation: 372

First of all, your JSON structure is weird, it is supposed to contain an array of objects. it should be something like this:

{
  "data": [
    {
      "cn": "Hermes Conrad",
      "description": "Human",
      "mail": "[email protected]",
      "ou": "Office Management",
      "sn": "Conrad",
      "uid": "hermes"
    },
    {
        "cn": "someone else",
        "description": "Human",
        "mail": "[email protected]",
        "ou": "pqr",
        "sn": "xyz",
        "uid": "def"
      }
  ]
}

Convert the JSON to a JavaScript Object

const jsObj = JSON.parse(jsonObj);

Now that the JSON is converted to JS object, data will be an array of objects

Now, you can map it like you would normally do:

{jsObj.data.map(x => (
    <TableRow key={x.cn}>
        <TableCell component="th" scope="row"> </TableCell>
        <TableCell align="left">{x.cn}</TableCell>
        <TableCell align="left">{x.description}</TableCell>
        <TableCell align="left">{x.mail}</TableCell>
        <TableCell align="left">{x.ou}</TableCell>
        <TableCell align="left">{x.sn}</TableCell>
        <TableCell align="left">{x.uid}</TableCell>
    </TableRow>
))}

Upvotes: 0

Diamond
Diamond

Reputation: 3448

You need to convert JSON object into Array typed data to use map.

Object.entries(jsonObj).map();

const jsonObj = {
  "cn": [
    "Hermes Conrad"
  ], 
  "description": [
    "Human"
  ], 
  "mail": [
    "[email protected]"
  ], 
  "ou": [
    "Office Management"
  ], 
  "sn": [
    "Conrad"
  ], 
  "uid": [
    "hermes"
  ]
};
Object.entries(jsonObj).map(([key, value], index) =>  console.log(`${index}. ${key}: ${value[0]}`));

So your component could be implemented like below;

   <TableRow>
      <TableCell component="th" scope="row"> </TableCell>
      {
         Object.entries(details).map(([key, value]) => (<TableCell align="left">{value[0]}</TableCell>)) 
      }
   </TableRow>

Upvotes: 2

Ali Elkhateeb
Ali Elkhateeb

Reputation: 3743

You cannot map on objects, it has to be array, otherwise you'll get:

Uncaught TypeError: data.map is not a function

To map on object data you could use Object.keys, here is your return:

  return (
    <div>
      <h1>User Details</h1>
      <Table size="small">
        <TableHead>
          <TableRow>
            <TableCell align="left">cn</TableCell>
            <TableCell align="left">description</TableCell>
            <TableCell align="left">mail</TableCell>
            <TableCell align="left">ou</TableCell>
            <TableCell align="left">sn</TableCell>
            <TableCell align="left">uid</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          <TableRow>
            {Object.keys(data).map(key => (
              <TableCell align="left" key={key}>
                {data[key][0]}
              </TableCell>
            ))}
          </TableRow>
        </TableBody>
      </Table>
    </div>
  );

And here is a working Sandbox

Upvotes: 0

MilosMarkoni
MilosMarkoni

Reputation: 96

You have to select the first element from each array, so place [0] inside each element.

const classes = useStyles()


  return (

     <div className={classes.root} >
       <h1>User Details</h1>
       <Table className={classes.table} size="small">
         <TableHead>
           <TableRow>
             <TableCell align="left">cn</TableCell>
             <TableCell align="left">description</TableCell>
             <TableCell align="left">mail</TableCell>
             <TableCell align="left">ou</TableCell>
             <TableCell align="left">sn</TableCell>
             <TableCell align="left">uid</TableCell>
           </TableRow>
         </TableHead>
         <TableBody>
           {data.map(details => (
             <TableRow key={details.cn[0]}>
               <TableCell component="th" scope="row"> </TableCell>
               <TableCell align="left">{details.cn[0]}</TableCell>
               <TableCell align="left">{details.description[0]}</TableCell>
               <TableCell align="left">{details.mail[0]}</TableCell>
               <TableCell align="left">{details.ou[0]}</TableCell>
               <TableCell align="left">{details.sn[0]}</TableCell>
               <TableCell align="left">{details.uid[0]}</TableCell>
             </TableRow>
           ))}
         </TableBody>
       </Table>
     </div>
   )
}

Upvotes: 0

Related Questions