How can I render data within nested objects in react? - reactjs

I am working with an API that contains nested objects and I am not sure how to display it. I am reading about using Object.keys but not sure how to do it... help please...
Here is the react code. I need to render prices dynamically.
<div>
<Table responsive striped bordered hover variant="dark">
<thead>
<tr>
<th>Rank</th>
<th>Name</th>
<th>Symbol</th>
<th>Price</th>
<th>% Change</th>
<th>Market Cap</th>
</tr>
</thead>
<tbody>
{Object.keys(
cryptos.map(crypto => (
<tr key={crypto.id}>
<td>{crypto.cmc_rank}</td>
<td>
<Link to={`/crypto/${crypto.id}`}>{crypto.name}</Link>
</td>
<td>{crypto.symbol}</td>
<td>{`price should be displayed here `}</td>
<td>{`price change should be displayed here `}</td>
<td>{`market cap should be displayed here `}</td>
</tr>
))
)}
</tbody>
</Table>
</div>
Here is the data source
"data": [
{
"id": 1,
"name": "Bitcoin",
"symbol": "BTC",
"slug": "bitcoin",
"num_market_pairs": 8203,
"date_added": "2013-04-28T00:00:00.000Z",
"tags": [
"mineable"
],
"max_supply": 21000000,
"circulating_supply": 18376356,
"total_supply": 18376356,
"platform": null,
"cmc_rank": 1,
"last_updated": "2020-05-13T10:30:30.000Z",
"quote": {
"USD": {
"price": 8920.68810523,
"volume_24h": 40828691066.513,
"percent_change_1h": 0.107841,
"percent_change_24h": 1.62343,
"percent_change_7d": -2.5838,
"market_cap": 163929740386.67194,
"last_updated": "2020-05-13T10:30:30.000Z"
}
}
},

Here you go with a solution
<div>
<Table responsive striped bordered hover variant="dark">
<thead>
<tr>
<th>Rank</th>
<th>Name</th>
<th>Symbol</th>
<th>Price</th>
<th>% Change</th>
<th>Market Cap</th>
</tr>
</thead>
<tbody>
{
cryptos.length &&
cryptos.map(crypto => (
<tr key={crypto.id}>
<td>{crypto.cmc_rank}</td>
<td>
<Link to={`/crypto/${crypto.id}`}>{crypto.name}</Link>
</td>
<td>{crypto.symbol}</td>
<td>{crypto.quote.USD.price}</td>
<td>{crypto.quote.USD.price * crypto.quote.USD.percent_change_1h}</td>
<td>{crypto.quote.USD.market_cap}</td>
</tr>
)
)}
</tbody>
</Table>
</div>
Here is the data source
"data": [
{
"id": 1,
"name": "Bitcoin",
"symbol": "BTC",
"slug": "bitcoin",
"num_market_pairs": 8203,
"date_added": "2013-04-28T00:00:00.000Z",
"tags": [
"mineable"
],
"max_supply": 21000000,
"circulating_supply": 18376356,
"total_supply": 18376356,
"platform": null,
"cmc_rank": 1,
"last_updated": "2020-05-13T10:30:30.000Z",
"quote": {
"USD": {
"price": 8920.68810523,
"volume_24h": 40828691066.513,
"percent_change_1h": 0.107841,
"percent_change_24h": 1.62343,
"percent_change_7d": -2.5838,
"market_cap": 163929740386.67194,
"last_updated": "2020-05-13T10:30:30.000Z"
}
}
},
Price changed I have considered percent_change_1h * price. Check for cryptos.length before doing map operation.

I have no idea why you have {Object.keys( in there... remove it.
<div>
<Table responsive striped bordered hover variant="dark">
<thead>
<tr>
<th>Rank</th>
<th>Name</th>
<th>Symbol</th>
<th>Price</th>
<th>% Change</th>
<th>Market Cap</th>
</tr>
</thead>
<tbody>
{ cryptos.map(crypto => (
<tr key={crypto.id}>
<td>{crypto.cmc_rank}</td>
<td>
<Link to={`/crypto/${crypto.id}`}>{crypto.name}</Link>
</td>
<td>{crypto.symbol}</td>
<td>{`price should be displayed here `}</td>
<td>{`price change should be displayed here `}</td>
<td>{`market cap should be displayed here `}</td>
</tr>
)) }
</tbody>
</Table>
</div>
Having Object.keys() essentially returns an array containing the indexes of the array you map from cryptos. React needs an array of elements, so you just need iterate through the elements of cryptos, and map each item to something React can render.
For example:
const dataList = [{ key:'a', value:'Hello' }, { key:'b', value:'World' }];
<div>
{ dataList.map(data => <div key={ data.key }>{ data.value }</div>) }
</div>
Will render
<div>
<div>Hello</div>
<div>World</div>
</div>

Related

How To Conditional Render Data From 2 Data Sources Using React

I am rendering data from two JSON files in react. First file is my main file and from the second file I want conditional rendering on the basis of the first file.
Explanation: From First file name "maindata.json" I am rendering all the data into a table. There is a Unique id field in the Json in first file. From Second file I just want to populate only a date fieldand there is also a unique id in the second JSON. What I want is if the main JSon file id matches with the id in the second json file, so print the date from the second file in the same row next to the id from the main file.
What I have done.
I have applied the condition but the problem is its not doing the match and prints all the dates in one column.
React App is getting slower ( performance Issue )
Here is my Code sample.
import React, { Component } from "react";
import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
import ReactHTMLTableToExcel from 'react-html-table-to-excel';
import data from "./data/maindata.json";
import data1 from "./data/data2.json";
class PenApprovals extends Component {
render() {
return (
<div className="container-fluid" style={{ backgroundColor: '#f7f7f7' }}>
<table id="table-to-xls" className="table table-responsive table-striped display nowrap" >
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">Date</th>
<th scope="col">Status</th>
<th scope="col">Name</th>
</tr>
</thead>
<tbody>
{data.map((record) => (
<tr>
<td>{record.UniqueName}</td>
<td>
{data1.map((item) =>
<React.Fragment>
//Here fetching date from second file
{item.uniqueName === <span>{record.UniqueName}</span> ? <span>
{item.assignedDate}</span> : "NO Match Found" }
</React.Fragment>
)}
</td>
<td>{record.Status }</td>
<td>{record.Name}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
export default PenApprovals;
here is JSON Sample.
Main Data File
[
{
"UniqueName": "CR30876",
"StatusString": "Submitted",
"Name": "Pegasus Test 1"
},
{
"UniqueName": "CR35876",
"StatusString": "Submitted",
"Name": "Pegasus Test 1"
}
]
Second Conditional JSON File sample
[
{
"uniqueName": "CR35876",
"assignedDate": "2020-11-09",
},
{
"uniqueName": "CR34523",
"assignedDate": "2020-11-09",
}
//More records....
]
Thanks Everyone.
You should use filter instead of map! Here's the code that works.
class PenApprovals extends Component {
render() {
return (
<div className="container-fluid" style={{ backgroundColor: "#f7f7f7" }}>
<table
id="table-to-xls"
className="table table-responsive table-striped display nowrap"
>
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">Date</th>
<th scope="col">Status</th>
<th scope="col">Name</th>
</tr>
</thead>
<tbody>
{data.map((record) => {
const tgt = data1.filter(
(item) => item.uniqueName === record.UniqueName
);
return (
<tr>
<td>{record.UniqueName}</td>
<td>
{tgt.length
? tgt.map((item) => (
<React.Fragment key={item.uniqueName}>
<span>{item.assignedDate}</span>
</React.Fragment>
))
: "NO Match Found"}
</td>
<td>{record.StatusString}</td>
<td>{record.Name}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
export default PenApprovals;

react hooks toggle for specific row

Please clarify my problem of toggle for specific row of the table with react hooks. whenever I press click.. it opens for every row and by default the table head is moving right it is not constant.
Error in toggleHidden(key). How to correct my toggleHidden function?
const[isHidden , setIsHidden] = React.useState(true)
const toggleHidden = () => setIsHidden(!isHidden)
const data = [
{
"name": "gvf",
"email": "abc",
"companyname": "xyz",
"address": "abcy"
},
{
"name": "abi",
"email": "dhf",
"companyname": "dhd",
"address": "fhfh"
}
]
return (
<div>
<Row>
<Col>
<table className="table table-hover table-striped table-sm">
<thead className="thead-dark">
<tr>
<th>Name</th>
<th>Email</th>
<th>CompanyName</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{data.map((a , key) => (
<tr key={a.name}>
<td><Button onClick = {toggleHidden(key)}>Click</Button>
{!isHidden && <p>Hello ABIII</p> }
</td>
<td>{a.name}</td>
<td>{a.email}</td>
<td>{a.address}</td>
<td>{a.companyname}</td>
</tr>
))}
</tbody>
</table>
</Col>
</Row> </div>
you need define the specific row - when You mapping:
{data.map(a => (
)}
try add key attribute to every item in collection like this:
{data.map((a, key) => (
))}
then pass to Your item:
<tr key={key}>
So now every is unique - so if You pass that key to your function:
<Button onClick = {toggleHidden(key)}>
the program should know which specific item execute toggleHidden function

Toggle specific row with hooks

Error in toggleHidden(key) [error: expecting 0 args but got 1] . kindly suggest corrections top toggle with key for particular row.
code
const [isOpen, setIsOpen] = React.useState(false);
const toggle = () => setIsOpen(!isOpen);
const[isHidden , setIsHidden] = React.useState(true)
const toggleHidden = () => setIsHidden(!isHidden)
const data = [
{
"name": "gvf",
"email": "abc",
"companyname": "xyz",
"address": "abcy"
},
{
"name": "abi",
"email": "dhf",
"companyname": "dhd",
"address": "fhfh"
}
]
return (
<div>
<Row>
<Col>
<table className="table table-hover table-striped table-sm">
<thead className="thead-dark">
<tr>
<th>Name</th>
<th>Email</th>
<th>CompanyName</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{data.map((a , key) => (
<tr key={key}>
<td><Button onClick = {toggleHidden}>Click</Button>
{!isHidden && <p>Hello ABIII</p> }
</td>
<td>{a.name}</td>
<td>{a.email}</td>
<td>{a.address}</td>
<td>{a.companyname}</td>
</tr>
))}
</tbody>
</table>
</Col>
)
}
Just change the state to be an array and "pop"/"push" keys into it on toggle, then declare a curried handler that accepts a key, and performs proper toggle logic. I removed isOpen state since it was not used in the example, however you can change it the same way that isHidden state and toggler was changed:
const [ isHiddenList, setIsHiddenList ] = React.useState([])
const toggleHidden = key => () => {
setIsHiddenList(
isHiddenList.includes(key)
? isHiddenList.filter(existingKey => existingKey !== key)
: [ ...isHiddenList, key ]
);
};
const data = [
{
"key": "1"
"name": "gvf",
"email": "abc",
"companyname": "xyz",
"address": "abcy"
},
{
"key": "2"
"name": "abi",
"email": "dhf",
"companyname": "dhd",
"address": "fhfh"
}
]
return (
<div>
<Row>
<Col>
<table className="table table-hover table-striped table-sm">
<thead className="thead-dark">
<tr>
<th>Name</th>
<th>Email</th>
<th>CompanyName</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{
data.map(({ key, name, email, companyname, address }) => {
const isHidden = isHiddenList.includes(key);
return (
<tr key={key}>
<td><Button onClick={toggleHidden(key)}>Click</Button>
{!isHidden && <p>Hello ABIII</p> }
</td>
<td>{a.name}</td>
<td>{a.email}</td>
<td>{a.address}</td>
<td>{a.companyname}</td>
</tr>
);
})
}
</tbody>
</table>
</Col>
</Row>
</div>
)
disclaimer - key should be part of data items for consistency, dynamically generated iteration index does not guarantee that keys will be assigned properly.

how to map subarray by key of parent array reactjs

how to map subarray in react based on key of parent array?
I have tried mapping by id key of main array to map elements of dish_count array
<TableCell align="left">
{this.state.persons.map((items,name) =>
<div key={this.state.persons.id}>
{(typeof(items.dish_count)=="object")? (<div>
{ items.dish_count.map((subdata) =>
<table>
<td >
{subdata.meal_type}
</td>
</table>
)
}
</div>): (null)}</div>)}
</TableCell>
<TableCell align="left"> {this.state.persons.map((items,name) =>
<div key={this.state.persons.id} >{(typeof(items.dish_count)=="object")? (<div>
{
items.dish_count.map((subdata) =>
<table>
<td >
{subdata.dish_count}
</td>
</table>
)
}
</div>): (null)}</div>)}</TableCell>
i want to map subarray dish_count by key id of parent array .I am able to map but the mapping is multiple and is not exclusive by parent array key.dish_count is the subarray of package array
persons array
"data": [
{
"id": 1,
"name": "Gold",
"dish_count": [
{
"dish_count": 4,
"meal_type": "Starters"
},
{
"dish_count": 4,
"meal_type": "Main Course"
},
{
"dish_count": 4,
"meal_type": "Dessert"
},
{
"dish_count": 4,
"meal_type": "Lunch"
}
]
},
{
"id": 2,
"name": "Basic",
"dish_count": [
{
"dish_count": 2,
"meal_type": "Starters"
},
{
"dish_count": 2,
"meal_type": "Main Course"
},
{
"dish_count": 2,
"meal_type": "Dessert"
},
{
"dish_count": 2,
"meal_type": "Lunch"
}
]
}
]
I want
Meal Type No of Dishes
Gold Starters 4
Main Course 4
Desert 4
Lunch 4
Basic Starters 2
Main Course 2
Desert 2
Lunch 2
You have a few problems in your code:
this.state({persons:''});: This will set the initial persons to be an empty string and will fail with map.
console.log('package',this.state.persons): setState is async and the console.log will not print the desired state but the previous state. Use the callback of setState as second parameter to access the new state:
this.setState({persons:res.data.data.data}, () => console.log('package',this.state.persons) );
this.state.persons.map((items, name) =>: The map function will provide different parameters: the first is the person and the second is the index of that person within the array.
div key = {this.state.persons.id}: since persons is an array, the key will be undefined. If you use the map function correctly, you can use person.id.
When you fixed these problems, the code should work as expected.
To only show the expected dishes per person and not to print the duplication you have to write it like this:
class Table extends React.Component {
render() {
return <table>
<thead>
<tr>
<td>ID</td>
<td>Name</td>
<td>Meal Type</td>
<td>Number of Dishes</td>
</tr>
</thead>
<tbody>
{this.state.persons.map(person =>
<tr>
<td>{person.id}</td>
<td>{person.name}</td>
<td>
<table>
<tbody>
{person.dish_count.map(dish => <tr>
<td>{dish.meal_type}</td>
</tr>
)}
</tbody>
</table>
</td>
<td>
<table>
<tbody>
{person.dish_count.map(dish => <tr >
<td>{dish.dish_count}</td>
</tr>
)}
</tbody>
</table>
</td>
</tr>
)
}
</tbody>
</table >
}
}
By not iterating over the person for each sub-table, you can remove the duplicated data.
codepen
Hope this helps.

Smart Table search not working when creating multiple tables

This is what I am doing.
I call a rest api which returns response in this format
"metalanguages": {
"1": {
"id": 1,
"name": "Abkhaz"
},
"2": {
"id": 2,
"name": "Afar"
}
},
"manufacturers": {
"-1": {
"id": -1,
"name": "all"
},
"1": {
"id": 1,
"name": "RIM"
},
"2": {
"id": 2,
"name": "HP"
}
}
This is basically a Map of String and Map.
I now have to create n number of table where n is number of keys of original map and inside each table I have to show data which will be the value of internal map ("id": 2,
"name": "HP")
I have made it working but search is not working.
This is my sample code
<div ng-repeat="(key,value) in metadataDetails">
<table st-table="metadataCollection" st-safe-src="metadataDetails" class="table table-striped">
<thead>
<tr class="style_tr">
<th st-sort="name">name</th>
<th st-sort="name">name</th>
<th st-sort="description">description</th>
<th st-sort="countryName">countryName</th>
<th st-sort="carrierName">carrierName</th>
</tr>
<tr class="textSearchTr">
<th colspan="4" class="textSearchTr">
<input class="freshblue" placeholder="Enter value to search/filter" type="text" ng-model="searchParam.search" />
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in getValueMap(key)" ng-show="showRow">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
<td>{{row.description}}</td>
</tr>
</tbody>
</table>
</div>
And my js file
AuditMetadataService.get({}, function(data) {
$scope.numRecord = data.length;
$scope.metadataDetails = data;
$scope.metadataCollection = [].concat($scope.metadataDetails);
console.log("Return value :");
console.log($scope.metadataDetails);
});
$scope.getValueMap = function(key) {
console.log(key);
return $scope.metadataDetails[key];
};
Could someone please help??
You can turn your map object into an array by getting it's keys and using the Array.prototype.map function, you will have to repeat this for the inner map objects as well because st-sort expects an array item, not a key value.
$scope.tables = keys.map(function(key) {
return Object.keys(data[key]).map(function(k) {
return data[key][k];
});
});
Then you can iterate $scope.tables using ng-repeat to create all the tables want, clicking the column titles will now sort them properly.
Here is a demo.

Resources