Reputation: 425
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
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 -
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"
]
}
]
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
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
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
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
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
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