i am trying to Render a Table dynamically based on a JSON File. The header of the Table is working as expected but i don't know how i could achieve to render the Body based on the Layout which is defined in the JSON File and then use the Data i got using an API call.
This is how my JSON File looks like:
{
"Header": [
{
"Column": "Id"
},
{
"Column": "Account Name"
},
{
"Column": "City"
},
{
"Column": "Street"
},
{
"Column": "Created Date"
},
{
"Column": "Industry"
}
],
"Body": [
{
"Body": "id"
},
{
"Body": "accountName"
},
{
"Body": "city"
},
{
"Body": "street"
},
{
"Body": "createdDate"
},
{
"Body": "industry"
}
]
}
Here i am fetching the Data as well as the JSON:
const [header, setHeader] = useState([]);
const [body, setBody] = useState([]);
const [records, setRecords] = useState([]);
const fetchData = async () => {
axios.get("http://localhost:8080/api/v1/files/Account/AccountList")
.then(response => {
setHeader(response.data.Header);
setBody(response.data.Body);
})
axios.get(`http://localhost:8080/api/v1/${object}`)
.then(response => {
setRecords(response.data);
})
}
useEffect(() => {
fetchData();
}, []);
And this is how i render the Table:
<table className="Object-List--Table">
<thead>
<tr className="Object-List--Table-Header">
{header.map((head) => {
return (
<th className="Header-Column">{head.Column}</th>
);
})}
</tr>
</thead>
<tbody>
{records.map((record) => {
return (
<tr className="Object-List--Table--Body" key={record.id}>
<td className="Body-Column">
<Link to={`/${object}/${record.id}`}>{record.id}</Link>
</td>
<td className="Body-Column">{record.accountName}</td>
<td className="Body-Column">{record.city}</td>
<td className="Body-Column">{record.street}</td>
<td className="Body-Column">{record.createdDate}</td>
<td className="Body-Column">{record.industry}</td>
</tr>
);
})}
</tbody>
</table>
This is the Response i get when calling the API
[
{
"id": 1,
"accountName": "Rainer Zufall",
"city": "Dortmund",
"street": "Teststraße 42",
"createdDate": "2021-01-03T23:00:00.000+00:00",
"industry": "Developer"
},
{
"id": 2,
"accountName": "7z226b46",
"city": "ngw4125",
"street": "t3rxjo4v 34",
"createdDate": "2020-01-06T00:00:00.000+00:00",
"industry": "Developer"
}
]
My question is now, how i could achieve to render the Body of the Table based on the Records i am getting through the API as well as through the Body which is defined in the JSON File.
I would like to have the Body of the table like this:
<td className="Body-Column">{record[body].Body}</td>
Pls use below code for tbody map.
records.Body.map( record => {
<tr>
<td className="Body-Column">{record.Body}</td>
...
</tr>
});
records.map((record) => {
return (
<tr className="Object-List--Table--Body" key={record.id}>
<td className="Body-Column">{record.accountName}</td>
...
</tr>
);
})
I tried how to do this and i found a Solution for my Problem. If anyone else has something like this, this is the Code i am using for the Moment:
{records.map((record, index) => {
return (
<tr className="Object-List--Table--Body" key={`Row-${index}`}>
{
body.map((row, index) => {
return (
<td
className="Body-Column"
key={`Cell-${index}`}>{record[row.Body]}</td>
);
})
}
</tr>
);
})}
Related
I am having trouble displaying the arr dummy API into columns similar to the below image, where each column has a header followed by their children, but however, I am getting everything inside the first column when it should be parent > child
layout data rendering
I am getting the following UI
const arr = [
{
"demo": [
{
"_id": "xx122",
"name": "Historian",
"tags": [
"demo"
],
"things": [],
"list": [],
"queries": [],
"notes": []
}
],
"demo_2": [
{
"_id": "xx123",
"name": "Demo",
"tags": [
"demo_2"
],
"things": [],
"list": [],
"queries": [],
"notes": []
}
],
}
]
const modArray = Object.keys(arr[0]).map(i => {
return {id: i, ...arr[0][i]}
});
export default function Demo() {
return (
<div>
<table className="table">
<thead>
<tr>
{modArray.map((i) => (
<th key={i.id}>{i.id}</th>
))}
</tr>
</thead>
<tbody>
{modArray.map((items, index) => {
console.log(items.id);
return (
<tr key={items.id}>
{Object.keys(items).map((key) => {
console.log(items[key]._id);
return <td key={items[key]._id}>{items[key]._id}</td>;
})}
</tr>
);
})}
</tbody>
</table>
</div>
);
}
This is because you are returning a row for each item in the array, rather than a column. It should look just like the head. Here's an example of the pattern.
<tr> // wrapper row
{modArray.map((items) => {
return (
<td key={items.id}>
<table>
<tr>{/* keys map logic goes here */}</tr>
</table>
</td>
)
})}
</tr>
I am trying to create table from the given json. here is json Structure. i am using simple html table to make table structure same like mentioned in below snapshot.as data's are dynamic table structure is not displaying proper in my case.
{
"e_id": "1234",
"e_o_name": "Contact_info",
"matching_details": [
{
"me_value": "value1",
"matching_attributes": [
{
"me_id": "1234",
"me_name": "28 sai",
"me_list": [
{
"me_type": "Email ID",
"me_email_list": [
{
"me_value": "a#gmail"
},
{
"me_value": "b#gmail"
}
],
"me_percent": "100"
}
]
},
{
"me_id": "5678",
"me_name": "29 meena",
"me_list": [
{
"me_type": "Email ID",
"me_email_list": [
{
"me_value": "c#gmail.com"
},
{
"me_value": ",d#gmail.com"
}
],
"me_percent": "100"
}
]
}
]
},
{
"me_value": "value2",
"matching_attributes": [
{
"me_id": "1234",
"me_name": "rimzim",
"me_list": [
{
"me_type": "Email ID",
"me_email_list": [
{
"me_value": "p#gmail"
},
{
"me_value": "q#gmail"
}
],
"me_percent": "100"
}
]
},
{
"me_id": "5678",
"me_name": "ranu",
"me_list": [
{
"me_type": "Email ID",
"me_email_list": [
{
"me_value": "t#gmail.com"
},
{
"me_value": ",u#gmail.com"
}
],
"me_percent": "100"
}
]
}
]
},
]}
above structure is the actual output.I tried creating the same but for
me data's are coming in single row.
enter code here<table>
<tbody>
<tr>
<th>contact</th>
<th>ty</th>
<th>ed</th>
<th>mail</th>
<th>percent</th>
</tr>
<tr>
<td rowspan="4">data.e_o_name</td>
<td rowspan="2" *ngFor="let match of data.matching_details">{{match.me_value}}</td>
<td>28 sai</td>
<th>a#gmail,b#gmail</th>
<td>100</td>
</tr>
</tbody>
Help for the same is highly appriciated... Thanks in advance
I would prepare proper table rows structure in order to render this complex table.
component.ts(or service.ts)
rows = [];
generateTable() {
if (!this.data) {
return;
}
this.rows.push([
{
text: this.data.e_o_name,
rowspan: 0
}
]);
let maxRowSpan = 0;
this.data.matching_details.forEach((detail, i) => {
const elemRowSpan = Math.max(detail.matching_attributes.length, 1);
maxRowSpan += elemRowSpan;
if (i > 0) {
this.rows.push([])
}
this.rows[this.rows.length - 1].push({
text: detail.me_value,
rowspan: elemRowSpan
});
detail.matching_attributes.forEach((attr, j) => {
if (j > 0) {
this.rows.push([])
}
const mail = attr.me_list[0];
this.rows[this.rows.length - 1].push(
{
text: attr.me_name,
rowspan: 1
},
{
text: mail.me_email_list.map(({ me_value }) => me_value).join(', '),
rowspan: 1
},
{
text: mail.me_percent,
rowspan: 1
}
);
})
});
this.rows[0][0].rowspan = maxRowSpan;
}
template.html
<table>
<tbody>
<tr>
<th>contact</th>
<th>ty</th>
<th>ed</th>
<th>mail</th>
<th>percent</th>
</tr>
<tr *ngFor="let row of rows">
<td *ngFor="let col of row" [attr.rowSpan]="col.rowspan">{{ col.text }}</td>
</tr>
</tbody>
</table>
Ng-run Example
So I am making a GET call in React using the fetch library. This is the schema:
{
"originatingRequest": {
"clientId": 1,
"simulationName": "Season 2020",
"teamRatings": [{
"teamId": 1,
"rating": 2.5
},
{
"teamId": 2,
"rating": 0.85
},
{
"teamId": 3,
"rating": 1.35
},
{
"teamId": 4,
"rating": 1.35
}
],
"simulationId": "7d49cb14-d99e-4315-bba3-077d114ab6fc"
},
"markets": [{
"name": "Winner",
"selections": [{
"name": "Manchester City",
"probability": "0.25"
},
{
"name": "Manchester United",
"probability": "0.25"
},
{
"name": "Liverpool",
"probability": "0.25"
},
{
"name": "Chelsea",
"probability": "0.25"
}
]
},
{
"name": "Top Two",
"selections": [{
"name": "Manchester City",
"probability": "0.95"
},
{
"name": "Manchester United",
"probability": "0.05"
},
{
"name": "Liverpool",
"probability": "0.95"
},
{
"name": "Chelsea",
"probability": "0.05"
}
]
}
],
"created": "2020-05-27T11:12:43.467644"
}
I'm interested in the markets array, and want the probabilities returned for the Winner market in a Table. This component is rendered off a redirect, hence the useLocation() to get the parameter Id.
I got directed to optional chaining the other day, so I do some checking to see if there are any values in the object, if not return null. Even though the console.log() returns an object, it seems the final table is null:
function SimulationReport(props) {
const location = useLocation();
const [simResult, setSimResult] = useState(
getSimById(location.state.simId)
);
return (
<GridWrapper>
<div>
<TableWrapper>
<Table striped bordered hover size="sm" responsive>
<thead>
<tr className="same-col-widths">
<th>Team Name</th>
<th>Win Probability</th>
</tr>
</thead>
<tbody>
{simResult?.markets?.length
? simResult.markets
.find(t => t.name === "Winner")
.selections.map(selection => (
<tr key="">
<td>{selection.name}</td>
<td>{selection.probability}</td>
</tr>
))
: null}
</tbody>
</Table>
</TableWrapper>
</div>
</GridWrapper>
);
}
export default SimulationReport;
This is the call to the API that has been exposed:
export function getSimById(simId) {
return fetch(simsUrl + "/results/" + simId, {
method: "GET"
})
.then(handleResponse)
.catch(handleError);
}
And the response handling:
export async function handleResponse(response) {
if (response.ok) {
let someResponse = response.json();
console.log("loading response");
console.log(someResponse);
return someResponse;
}
if (response.status === 400) {
// So, a server-side validation error occurred.
// Server side validation returns a string error message, so parse as text instead of json.
throw new Error(error);
}
const error = await response.text();
console.log("error was: " + error);
console.log("status was: " + response.status);
throw new Error("Network response was not ok.");
}
// In a real app, would likely call an error logging service.
export function handleError(error) {
// eslint-disable-next-line no-console
console.error("API call failed. " + error);
throw error;
}
How do I populate the final rendered Table with the Winner market probabilities?
I tried the below 2 options but both are not working.
JSON
{
"Properties": [
{
"Type": "LEI"
},
{
"Country": "DE"
},
{
"Name": "Credit Institution"
}
]
}
Angular Typescript
Option #1
<ng-template pTemplate="body" let-entity>
<tr>
<td>{{entity.Properties[Type]}}</td>
<td>{{entity.Properties[Country]}}</td>
<td>{{entity.Properties[Name]}}</td>
</tr>
</ng-template>
Option #2
<ng-template pTemplate="body" let-entity>
<tr>
<td>{{entity.Properties.Type}}</td>
<td>{{entity.Properties.Country}}</td>
<td>{{entity.Properties.Name}}</td>
</tr>
</ng-template>
Update:-
My real JSON
{
"_id": "5bcb2dbfe8ffdd1bd0913825",
"_entitykey": "CRD_CRE_INS.CRDINSLEICODE",
"_validfrom": "2018-10-20T13:31:35.040Z",
"_validto": "2100-12-31T00:00:00.000Z",
"_datahash": "84f28a3fed7d3a1e5e2b21e5bc91e8a1",
"_payload": {
"CA_OwnerID": "EU_ECB",
"EntityCode": "CRDINSLEICODE",
"EntityType": "CRD_CRE_INS",
"Properties": [{
"EEA_DEP_GUA_SCH": [
"IS_TIF",
"GB_FSCS"
]
},
{
"ENT_AU": [
"2017-09-05",
"2018-10-05",
"2019-01-01"
]
},
{
"ENT_COD_TYP": "LEI"
},
{
"ENT_COU_RES": "DE"
},
{
"ENT_NAM": "Credit Institution In Germany"
},
{
"ENT_NAT_REF_COD": "REFCODE12342"
},
{
"ENT_TOW_CIT_RES": "GERMAN TOWN1243"
},
{
"INT_CAP_REQ_UND_ART_12": "ART_12_1_CRD"
},
{
"TYP_UND_ACC_CRR_ART_27": "ART_27_1_A1_CRR"
},
{
"IS_HID_NOT_PUB": "0"
}
],
"Services": [{
"DE": [
"PS_010",
"PS_020",
"PS_03A",
"PS_03B"
]
},
{
"GR": [
"PS_010",
"PS_020"
]
}
]
}
}
I have created a sample application to bind property dynamically on stackblitz
Here is the component code.
data = {
"Properties": [
{
"Type": "LEI"
},
{
"Country": "DE"
},
{
"Name": "Credit Institution"
}
]
}
columns:string[] = [];
ngOnInit(){
for(let row of this.data.Properties){
for(var columnName in row){
this.columns.push(columnName)
}
}
}
Here is the Html Code.
<table>
<tr *ngFor="let row of data.Properties; let i = index">
<td >{{row[columns[i]]}}</td>
</tr>
</table>
First you need to create a columns array and bind that in the html.
Please let me know if you have any question.
I think your best bet is to map the properties into a single structure and then you can access the properties as you want to.
The resulting structure would look like the following:
{
"Type": "LEI",
"Country": "DE",
"Name": "Credit Institution"
}
So you will be accessing a single object instead of an array of objects with different properties, like so:
var entity = {
"Properties": ([
{
"Type": "LEI"
},
{
"Country": "DE"
},
{
"Name": "Credit Institution"
}
]).reduce((res, curr) => Object.assign(res, curr), {})
}
console.log(entity.Properties)
<ng-template pTemplate="body" let-entity>
<tr>
<td>{{entity.Properties.Type}}</td>
<td>{{entity.Properties.Country}}</td>
<td>{{entity.Properties.Name}}</td>
</tr>
</ng-template>
Or, if you want to show all properties, you can do so dynamically, like so:
<ng-template pTemplate="body" let-entity>
<tr>
<td *ngFor="let key of entity.Properties">{{entity.Properties[key]}}</td>
</tr>
</ng-template>
I have an app that are retrieving 2 sets of data. Now I want to do is get the brand of data1 and and the brand of data2 which depends on the date, if true it will render the amount of data2.
so far this is my code
-my data
const data1 = [
{
"data1result": [
{
"brand": "brand1"
},
{
"brand": "brand2"
},
{
"brand": "brand3"
},
{
"brand": "brand4"
}
]
}
];
const data2 = [
{
"data2result": [
{
"date": "12-01",
"details": [
{
"amount": 24250,
"brand": "brand1"
},
{
"amount": 68350,
"brand": "brand2"
},
{
"amount": 60,
"brand": "brand3"
},
{
"amount": 11078,
"brand": "brand4"
}
]
},
{
"date": "12-02",
"details": [
{
"amount": 27340,
"brand": "brand1"
},
{
"amount": 16500,
"brand": "brand2"
},
{
"amount": 210,
"brand": "brand3"
},
{
"amount": 23229,
"brand": "brand4"
}
]
},
]
}
];
and as for my code
export default React.createClass({
render() {
<table>
<thead>
<tr>
<th></th>
{
data1.map(function(i) {
return <th>{i.data1result.brand}</th>;
})
}
</tr>
</thead>
<tbody>
{data2.map(function(a) {
return (
<tr className="salesTarget">
<td className="td-fixed"><b>{a.data2result.date}</b></td>
//help me here
<td className="td-fixed">brand1 amount of date **-**</td>
<td className="td-fixed">brand2 amount of date **-**</td>
<td className="td-fixed">brand3 amount of date **-**</td>
<td className="td-fixed">brand4 amount of date **-**</td>
</tr>
)
})}
</tbody>
</table>
}
})
and the result should be like this
You can map over an array and not an object. In your case to render the brand amounts just create a nested map function assuming the order of brand values is the same. Also have a look at how the outer map is created. Also you must have a return statement in you react class .
var App = React.createClass({
render() {
const data1=[{data1result:[{brand:"brand1"},{brand:"brand2"},{brand:"brand3"},{brand:"brand4"}]}];
const data2=[{data2result:[{date:"12-01",details:[{amount:24250,brand:"brand1"},{amount:68350,brand:"brand2"},{amount:60,brand:"brand3"},{amount:11078,brand:"brand4"}]},{date:"12-02",details:[{amount:27340,brand:"brand1"},{amount:16500,brand:"brand2"},{amount:210,brand:"brand3"},{amount:23229,brand:"brand4"}]}]}];
return (
<table>
<thead>
<tr>
<th></th>
{
data1[0].data1result.map(function(i) {
return <th>{i.brand}</th>;
})
}
</tr>
</thead>
<tbody>
{data2[0].data2result.map(function(a) {
return (
<tr className="salesTarget">
<td className="td-fixed"><b>{a.date}</b></td>
{a.details.map(function(item){
return (
<td className="td-fixed">{item.amount}</td>
)
})}
</tr>
)
})}
</tbody>
</table>
)
}
})
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Adding a map to your data2result[].details, you should be able to render the columns for each brand:
export default React.createClass({
render() {
<table>
<thead>
<tr>
<th></th>
{
data1.map(function(i) {
return <th>{ i.data1result.brand }</th>;
})
}
</tr>
</thead>
<tbody>
{
data2.map(function(a) {
return (
<tr className="salesTarget">
<td className="td-fixed"><b>{ a.data2result.date }</b></td>
{
a.details.map(function(b) {
<td className="td-fixed">{ b.amount }</td>
})
}
</tr>
)
})
}
</tbody>
</table>
}
})
You can try something like this:
Note: This answer just address part of processing data and not binding values to React UI
const data1=[{data1result:[{brand:"brand1"},{brand:"brand2"},{brand:"brand3"},{brand:"brand4"}]}];
const data2=[{data2result:[{date:"12-01",details:[{amount:24250,brand:"brand1"},{amount:68350,brand:"brand2"},{amount:60,brand:"brand3"},{amount:11078,brand:"brand4"}]},{date:"12-02",details:[{amount:27340,brand:"brand1"},{amount:16500,brand:"brand2"},{amount:210,brand:"brand3"},{amount:23229,brand:"brand4"}]}]}];
var result = {};
data1[0].data1result.forEach(function(brand){
data2[0].data2result.forEach(function(res){
result[res.date] = result[res.date] || {};
var amount = res.details.reduce(function(p,c){
p += c.brand === brand.brand ? c.amount : 0;
return p;
}, 0)
if(amount > 0)
result[res.date][brand.brand] = amount;
})
});
console.log(result)
Try this:
export default React.createClass({
render() {
<table>
<thead>
<tr>
<th></th>
{
data1[0].data1result.map(function(i) {
return <th>{ i.brand }</th>;
})
}
</tr>
</thead>
<tbody>
{
data2[0].data2result.map(function(a) {
return (
<tr className="salesTarget">
<td className="td-fixed"><b>{ a.date }</b></td>
{
a.details.map(function(b) {
<td className="td-fixed">{ b.amount }</td>
})
}
</tr>
)
})
}
</tbody>
</table>
}
})