Amiry Amiry - 1 month ago 11
JSON Question

Handling complex data objects with Reactjs

I am trying to create a table of orders. I work with React+Redux.
I have my data stored in props.
The data is structured similar to this: (a bit more detailed)

[{ //stored in props(redux state)
"id": 37, //order 1
"content": {
"items": {
"47427": {
"price": "12.49",
"format": "[\"1x12\"]",
"quantity": 1,
},
"23451": {
"price": "18.99",
"format": "[\"1x7\"]",
"quantity": 1,
},
}
},
"address": {
"first_name": "Tyrion",
"last_name": "Lannister",
"line1": "The Red Keep",
"city": "King's Landing",
"country": "Westeros",
}
}, {
"id": 38, //order 2
"content": {
"items": {
"183429": {
"price": "8.99",
"format": "[\"1x7\"]",
"quantity": "1",
}
}
},
"address": {
"first_name": "Arya",
"last_name": "Stark",
"line1": "23 Wolf st.",
"city": "Winterfell",
"country": "Westeros",
}
}, {
"id": 30, //order 3
"content": {
"items": {
"20399": {
"price": "21.99",
"format": "[\"1x12\"]",
"quantity": 1,
}
}
},
"address": {
"first_name": "Jon",
"last_name": "Snow",
"line1": "29 Winter is here st.",
"city": "The Wall",
"country": "Westeros",
}
}]


I want to access the "content" and "address" properties of each order and display it in a table. So i tried to call orders.map() on this object but this only gives me access to the first layer of properties - for instance order.id.
When i try to access order.content.item.price i get an error "can't read property of undefined".

My question goes on about order.content.items. that's when i have another object to iterate over since it has different property names, that contain properties inside them (.price, .format, .quantity).
So basically, how do i handle this complex data, so I can grab every piece of info in this object and place them in my table?

//my render function of <OrdersTable />
render() {
let filter = this.props.filter || {};
let orders = this.props.orders || [];
let content = orders.map(order => {
return (
<tr key={order.id}>
<td>{order.content}</td>
</tr>
)
})
let address = orders.map(order => {
return (
<tr key={order.id}>
<td>{order.address.first_name}</td>
</tr>
)
})
return (
<div>
<button className="filter"
onClick={this.props.showContent}>
Show Content
</button>
<button className="filter"
onClick={this.props.showAddress}>
Show Address
</button>
<table className='orders'>
<thead className={filter.showContent?'content': 'content hidden'}>
<tr>
<th>Items</th>
<th>Format</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<thead className={filter.showAddress?'address': 'address hidden'}>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Country</th>
<th>City</th>
</tr>
</thead>
<tbody className={filter.showContent?'content': 'content hidden'}>
{content}
</tbody>
<tbody className={filter.showAddress?'address': 'address hidden'}>
{address}
</tbody>
</table>
</div>
)


Thank you very much :)

EDIT:
So here's what did the trick in my case: (with the help of @TW80000 and @TomDavies)

let content = orders.map(order => {
const items= Object.keys(order.content.items).map(id => {
const item= order.content.items[id];
return(
<tr key={id}>
<td>{id}</td>
<td>{item.format}</td>
<td>{item.quantity}</td>
<td>{item.price}</td>
</tr>
)
})
return items;
});
const address = orders.map(order => {
return (
<tr key={order.id}>
<td>{order.address.first_name}</td>
<td>{order.address.last_name}</td>
<td>{order.address.country}</td>
<td>{order.address.state}</td>
<td>{order.address.city}</td>
<td>{order.address.line1}</td>
<td>{order.address.zip}</td>
</tr>
)
});

...

<tbody className={filter.showContent?'content': 'content hidden'}>
{content}
</tbody>
<tbody className={filter.showAddress?'address': 'address hidden'}>
{address}
</tbody>

Answer Source

I want to access the "content" and "adress" properties of each order and display it in a table.

You've spelled address wrong pretty much everywhere, that could be why it's not being read correctly.

So i tried to call orders.map() on this object but this only gives me access to the first layer of properties - for instance order.id.

That's not true, you will have access to all properties: id, address, and content.

When i try to access order.content.item.price i get an error "can't read property of undefined".

That's because it's content.items with an "s", not content.item like you have written. content.item is undefined and that's why you get this error.

My question goes on about order.content.items. that's when i have another object to iterate over since it has different property names, that contain properties inside them (.price, .format, .quantity).

You can do a nested loop. Example:

let content = orders.map(order => {
  const tds = Object.keys(order.content.items).map(id => {
    const item = order.content.items[id];
    // You can use item.quality and item.format here as well
    return(<td>{item.price}</td>);
  })
  return (
    <tr key={order.id}>{tds}</tr>
  );
})