Generate Multiple Tables From A Single Map React - javascript

I'm trying to generate six different React bootstrap tables based on the groupName field of the below data (more objects inside, just used three for example):
CompetitionData.js
const data= {
"players": [],
"teams": [
{
"id": 1,
"name": "England",
"groupName": 4
},
{
"id": 2,
"name": "Germany",
"groupName": 6
},
{
"id": 4,
"name": "Russia",
"groupName": 2
}
]
}
export default data;
Currently I'm able to map through the data and generate a single table, but not sure how to loop through the data just once in order to generate six different tables...
Standings.js
import React from "react";
import { Table } from "react-bootstrap";
import CompetitionData from "../data/CompetitionData";
export const Standings = () => {
const data = CompetitionData;
return (
<Table striped bordered hover size="sm" variant ="dark">
<thead>
<tr>
<td>Country</td>
<td>Group</td>
</tr>
</thead>
<tbody>
{data?.teams?.length
? data.teams.map((team, index) => (
<tr key={index}>
<td>{team.name}</td>
<td>{team.groupName}</td>
</tr>
))
: null}
</tbody>
</Table>
);
};
Any idea how to go about doing that?

Related

how to give fixed table rows using typescript

I am using table for showing the datas and for data I am using Api.
Api data looks like::
{
"data": [
{
"id": "1",
"name": "name1",
"label": "label1"
},
{
"id": "2",
"name": "name2",
"label": "label2"
},
{
"id": "3",
"name": "name3",
"label": "label3"
}
]
}
html code
<table class="table table-striped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Label</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of sample;">
<td>{{data.id}}</td>
<td>{{data.name}}</td>
<td>{{data.label}}</td>
<tr>
<tbody>
<table>
I need the 10 table rows statically(fixed). The table data is from API. For exanple ,Api contains 2 data... Then UI table should be with 2 rows of data and balance with emply rows... but there should display 10 rows(Mandatory)
which means in UI i want 10 rows with data from Api and balance should be empty.
You can fix in view layer, ts layer or even backend API layer (Not really recommended).
In view layer if you loop over your data, you can calculate if your data's size goes over arbitrary threshold and if not loop again to display as many empty rows as possible.
In ts layer, when you receive data from api you can modify variable you pass to your view by adding to an array as many empty items as you need.
What's important if you use null, then you have to check for it with for example elvis operator.
I would advise agains adding to an array an object with all properties set to null, because then these are not so easily distinguishable from valid data from API and you can for instance make some rows interactive, even though they should not be.
const dataFromApi = [{ "id": "1", "name": "name1" }, { "id": "2", "name": "name2" }]
const minRowsNumber = 10;
const diff = minRowsNumber - dataFromApi.length;
const viewTableData = diff > 0 ? dataFromApi.concat(new Array(diff).fill(null)) : dataFromApi;
console.log(viewTableData)
Example in AngularJs (No Angular in SO Snippets, but it is the same principle)
angular.module('example', [])
.controller('ExampleController', function ExampleController() {
const dataFromApi = [{ "id": "1", "name": "name1" }, { "id": "2", "name": "name2" }]
const minRowsNumber = 10;
const diff = minRowsNumber - dataFromApi.length;
this.viewTableData = diff > 0 ? dataFromApi.concat(new Array(diff).fill(null)) : dataFromApi;
});
table {
border-collapse: collapse;
}
td, th {
border: 1px solid black
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="example" ng-controller="ExampleController as example">
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in example.viewTableData track by $index">
<td>{{row ? row.id : ' '}}</td>
<td>{{row ? row.name : ' '}}</td>
</tr>
</tbody>
</table>
</div>

Mapping table data 2D array

I have a slightly strange problem that i cant solve. I have to render a table using react - however my data structure is such that i need the name from the first level to be the table headings - I then need to map the data associated to that heading into the correct cells in the table.
Here is my data
[{
"cell_id": 1,
"step_data": [{
"width": 1920,
"name": "bruce",
}, {
"width": 2236,
"name": "ben",
}],
"cell_name": " boys names"
},
{
"cell_id": 2,
"step_data": [{
"width": 1920,
"name": "grace",
}, {
"width": 2236,
"name": "megan",
}],
"cell_name": "girls names"
}
To map the table headings i do this which dynamically renders the headings however I cant seem to put the data under the correct headings as they all go on the same row.
Any ideas how i do this?
My desired task is to have a table with two headings boys names and girls names - I need the step_data from boys names to be rows under the boys name heading and the step data from girls names to be under the girls names heading
<table className="table">
<tbody>
<tr>
{this.props.data.map((item, key) => <th key={key}>{item.cell_name}</th>
)}
</tr>
{this.props.data.map(data => data.map((z, key) => <td key={key}>{z.name}</td>))}
<tr>
</tr>
</tbody>
</table>
{[
...Array( // get the number of rows you need to create
Math.max(...this.props.data.map(({ step_data }) => step_data.length))
).keys()
].map(i => (
<tr key={i}>
{this.props.data.map(({ step_data, cell_name }) => (
<td key={cell_name}>{(step_data[i] || {}).name}</td>
))}
</tr>
))}

ReactJS: How to render columns horizontally

I am facing an issue to order the columns of a fetched API data horizontally. I am trying to print the data fetched from an API into a table. Anyhow the rows are well printed horizontally, but the function that I used for rows this.state.data.map() doesn't function in the same way for the columns. I think it's ES6 standard, but I am not sure. Here is my printed issue.
Here is my code sample:
class App extends React.Component
{
constructor()
{
super();
this.state = {
rows: [],
columns: []
}
}
componentDidMount()
{
fetch( "http://ickata.net/sag/api/staff/bonuses/" )
.then( function ( response )
{
return response.json();
} )
.then( data =>
{
this.setState( { rows: data.rows, columns: data.columns } );
} );
}
render()
{
return (
<div id="container" className="container">
<h1>Final Table with React JS</h1>
<table className="table">
<thead> {
this.state.columns.map(( column ) => (
<tr>
<th>{column[0]}</th>
<th>{column[1]}</th>
<th>{column[2]}</th>
<th>{column[3]}</th>
</tr>
) )}
</thead>
<tbody> {
this.state.rows.map(( row ) => (
<tr>
<td>{row[0]}</td>
<td>{row[1]}</td>
<td>{row[2]}</td>
<td>{row[3]}</td>
</tr>
) )
}
</tbody>
</table>
</div>
)
}
}
ReactDOM.render( <div id="container"><App /></div>, document.querySelector( 'body' ) );
I was able to print harcoded, if I give value to the 'th' elements, but I want to print it dynamically, in case the data within the API has been changed.
You are welcome to contribute directly to my Repo: Fetching API data into a table
Here is how looks like my example, when columns values has been hardcoded within 'th' elements.
Any suggestions will be appreciated!
var data = {
columns: [
"Full name",
"Job title",
"Age",
"Bonus",
],
rows: [
[
"John Smith",
"team lead front-end",
30,
444.08,
],
[
"Tom Jones",
"front-end developer",
25,
333.3,
],
[
"Deborah Barnes",
"front-end developer",
21,
233.66,
],
[
"Isaac Roberson",
"technical support",
44,
353,
],
[
"Josh Brown",
"team lead back-end",
35,
353,
],
[
"Chester Mckinney",
"back-end developer",
33,
223.27,
],
[
"Ora Burton",
"back-end developer",
32,
192.92,
],
[
"Jim Brown",
"technical support",
19,
98.99,
],
],
}
class App extends React.Component
{
constructor()
{
super();
this.state = {
rows: [],
columns: []
}
}
componentDidMount()
{
this.setState( { rows: data.rows, columns: data.columns } );
}
render()
{
return (
<div id="container" className="container">
<h1>Final Table with React JS</h1>
<table className="table">
<thead>
<tr>
{this.state.columns.map(( column, index ) => {
return (<th>{column}</th>)
}
)
}
</tr>
</thead>
<tbody> {
this.state.rows.map(( row ) => (
<tr>
<td>{row[0]}</td>
<td>{row[1]}</td>
<td>{row[2]}</td>
<td>{row[3]}</td>
</tr>
) )
}
</tbody>
</table>
</div>
)
}
}
ReactDOM.render( <div id="container"><App /></div>, document.querySelector( 'body' ) );
<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>
Hope it may help
Not sure why you wanted to do columns[0], [1], [2] and [3]. Each column inside the map is a string. If you do columns[0] it will return you the first character from that which is what is happening in your case. Full Name, Job title, Age Bonus are rendered in your first image. First four characters in your columns.
The key attribute I added is just React's requirement to provide unique keys and has nothing to do with the problem.
this.state.columns.map((column, index) => (
<tr>
<th key={"columns-" + index.toString()}>
{column}
</th>
</tr>
))

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>
Since you are working with complex data, I'd rather separate everything into small subcomponents so it get's easier to use and understand the code later.
// Only order details
const OrderRow = (order) => {
return (
<tr>
{
Object.keys(order.content.items).map((key, index) => {
const item = order.content.items[key]
return (
<td key={index}>{item.price} {item.format} {item.quantity}</td>
)
})
}
</tr>
)
}
// Only address details
const AddressRow = (address) => {
return (
<tr>
<td>{adress.first_name}</td>
</tr>
)
}
// In your main component, render them all
render() {
...
return (
<table>
...
<tbody>
{orders.map(order => <OrderRow key={order.id} order={order} />)}
</tbody>
<tbody>
{orders.map(order => <AddressRow key={order.id} address={order.address} />)}
</tbody>
</table>
)
}
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>
);
})

Looping through the json service response in Angular JS

I am working on a angular project. i have a scenario where i need to list some details in a page of the application.I have a service call in the page which returns the following json structure. i want to loop through this json structure to list few of the data in the response.
[
{
"ProductDetails": [
{
"ProductType": "Application1",
"Name": "Product1",
"New": false,
"Category": "product",
"Country": "India",
"description": "Description for Product1",
"Favourite": false,
"settings": {
"WebsiteFlag": true,
"SmsFlag": false,
"EmailFlag": true
}
}
]
},
{
"ProductDetails": [
{
"ProductType": "Application2",
"Name": "Product2",
"New": true,
"Category": "product",
"Country": "India",
"description": "Description for Product2",
"Favourite": true,
"settings": {
"WebsiteFlag": false,
"SmsFlag": false,
"EmailFlag": true
}
}
]
}
]
JS
$ctrl.getSettings = function () {
var url = "http://localhost:3000/json/settings-updated.json";
rsicontext.getData(url).then(function (response) {
$ctrl.Settings = response.data;
});
}
HTML
<tbody>
<tr data-ng-repeat="app in $ctrl.Settings" class="content-box">
<td data-ng-bind="app.ProductDetails.ProductType"></td>
<td data-ng-bind="app.ProductDetails.Name"></td>
<td><ng-checkbox data-checked="app.SmsFlag" rounded="true"></ng-checkbox></td>
<td><ng-checkbox data-checked="app.EmailFlag" rounded="true"></ng-checkbox></td>
</tr>
</tbody>
I am trying to list the Product Type, Name, EmailFlag and SmsFlag. How can i loop through the json structure to list the data.
Simply go over the response and build a new array from the fields you need. Like so:
var d = [];
for( vari=0;i< response.data.ProductDetails.length; ++i) {
var curr= {
ProductType: response.data.ProductDetails[i].ProductType,
Name: response.data.ProductDetails[i].Name
}
d.push(curr);
}
$ctrl.Settings = d;
To manipulate object or array I always use a library called underscore.js
This can help you to do what you want.
var plucked=_.pluck($ctrl.Settings, 'ProductDetails');
This function will return an array of object. Then you can loop it.
https://jsfiddle.net/wz2njukj/
You can achieve this throw ng-repeat
<div ng-repeat="d in data[0].ProductDetails[0]">
{{ d.SmsFlag }} {{ d.WebsiteFlag}} {{d.EmailFlag}}
</div>
Look this and get data as you want.
PlunkerHere
ProductDetails contains an array, so you would have to nest ngRepeats
<span data-ng-repeat="detail in app.ProductDetails">
If you know that ProductDetails will only have one element it would be best to change the structure that is being generated if you can. If not you can access it in markup
<tbody>
<tr data-ng-repeat="app in $ctrl.Settings" class="content-box">
<td data-ng-bind="app.ProductDetails[0].ProductType"></td>
<td data-ng-bind="app.ProductDetails[0].Name"></td>
<td><ng-checkbox data-checked="app.ProductDetails[0].settings.SmsFlag" rounded="true"></ng-checkbox></td>
<td><ng-checkbox data-checked="app.ProductDetails[0].settings.EmailFlag" rounded="true"></ng-checkbox></td>
</tr>
</tbody>
Or you can massage the data in your controller before passing it off to the view.
$ctrl.Settings = response.data.map(products=>products.ProductDetails[0])

Categories