How to dynamically render jsx with objects values - javascript

Data is an array object. I want to render table columns dynamically according to data object. I used this same technique to generate table head its working. Is there any way to fix this issue?
const DataTable = ({data, deleteHandler, loading, tableFields}) => {
const thead = [];
const tbody = [];
const [values, setValues] = useState({});
for (const [key, value] of Object.entries(tableFields)) {
thead.push(<td>{value}</td>);
}
data.map((field) => {
for(const[key,value] of Object.entries(field)){
tbody.push(
<tr>
<td>{value}</td>
</tr>
);
}
})
return (
<Fragment>
<Card className={classes.__bk_admin_card}>
<Table borderless hover className={classes.__bk_admin_table}>
<thead>
<tr>
{thead}
</tr>
</thead>
<tbody>
{tbody}
</tbody>
</Table>
</Card>
</Fragment>
)
}

Related

Make a table and render the data inside a table using React

I'm trying to create a dynamic table so that every time I press the "add" button, a new row will be created.
In my example below, it creates only 1 row with all the data under its header, but with all the 3 values in this case instead of create a new row.
I'm fetching the document from Firestore and the collection includes only 1 document with an array inside, in this case with 3 values.
here is the screenshot of the table it creates:
Expecteed table example:
Code:
export default class NutritionTableOfTheUser extends Component {
constructor() {
super();
this.state = {
tableData: []
}
}
componentDidMount() {
const dbRef = collection(db, 'data');
onSnapshot(dbRef, (querySnapshot) => {
let foods = [];
querySnapshot.forEach(doc => {
foods.push(doc.data())
});
this.setState({ tableData: foods })
})
}
render() {
return (
<div className='container mt-3'>
{/* table */}
<table className='table table-hover'>
<thead>
<tr>
<th>#</th>
<th>Food</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
{this.state.tableData.map((row, index) => {
return (
<tr>
<td>{index + 1}</td>
<td>{row.value}</td>
<td>{row.quantity}</td>
</tr>
)
})}
</tbody>
</table>
</div>
)
}
}
You should check the data you are getting from firebase collection, because you might have only one document in collection which results in rendering only one row in table.
It looks like you only have a single document, and your .value and .quantity properties of the row are arrays (rather than numbers) - so doing <td>{row.value}</td> mashes all values of the array together.
Turn the .data() into the desired data format first, then set the state with it.
querySnapshot.forEach(doc => {
const [obj] = doc.data();
const tableData = obj.value.map((value, i) => ({
value,
quantity: obj.quantity[i]
}));
this.setState({ tableData })
});

ReactJS add table rows

I want an app.js that imports a component, that generates a row in a table for each element in an array.
import myRows from './myRows';
const myApp = ({ values}) => {
return (
<div>
<div>
{values.map((entry, index) => {
return <myRows entry={entry} key={index}/>
})}
</div>
</div>
)
}
...
const myRows = ({ entry}) => {
return (
**ROW ENTRY like row name = entry.name**
)
}
...
Maybe I should create in the my App.js a table and create in the map function a row for each entry in values? Idk how to do that.
I want a simple table where each row is created with each entry in values
My idea is not working and mybe it is stupid and there are many better ways..
import myRows from './myRows';
const myApp = ({ values}) => {
return (
<table>
<thead>
<tr>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
<th>5</th>
<th>6</th>
<th>7</th>
</tr>
</thead>
<tbody>
{values.map((entry, index) => {
return <myRows entry={entry} key={index}/>
})}
</tbody>
</table>
)
}
...
const myRows = ({ entry}) => {
return (
<tr>
<th>entry.name</th>
<td>entry.secondName</td>
<td>C</td>
<td>D1</td>
<td>entry.value22</td>
<td>E3</td>
<td>E4/</td>
</tr>
)
}
...
Don't use index as key. Each entry should have a unique identifier; either an id or you can interpolate some values to create a unique key for each row (e.g key={${row.name}_${row.createdAt}}
const App = ({ array }) => {
return <table>
<tbody>
{ array.map(row => <Row data={row} key={row.id} />) }
</tbody>
</table>
}
const Row = ({ data }) => {
return <tr>
<td>{data.name}</td>
<td>{data.created}</td>
...
</tr>
}

How to get text element of the given react component in React.cloneElement?

Developers give me the headings of the table:
const CustomersTable = () => {
var headers=<>
<th>Name</th>
<th>Age</th>
<th>Another text</th>
</>
return <Table
headers={headers}
/>
}
And this is the code of the Table component:
const Table = ({headers}) => {
var clonedHeaders = React.Children
.toArray(headers.props.children)
.map(header => React.cloneElement(header, {
className: "text-gray-900 py-3 font-light text-xs"
}));
return <table>
<thead>
<tr>
{clonedHeaders}
</tr>
</thead>
</table>
}
I can use React.cloneElement to add attributes to the elements I receive as props of my component.
However, I want to be able to change the text content of those received elements too.
For example, I want to call my locale translation function on table header elements, automatically. Right now, if developers want to make their tables multi-lingual, they should write this:
var headers = <>
<th>{t('Name')}</th>
<th>{t('Age')}</th>
<th>{t('Other text')}</th>
</>
I want to centralize that t(text) function for all headers prop. Can I do that?
You can use the same technique on the child elements of the headers as you do on the headers themselves:
const clonedHeaders = React.Children
.toArray(headers.props.children)
.map(header => React.cloneElement(header, {
className: "text-gray-900 py-3 font-light text-xs",
children: React.Children.toArray(header.props.children).map(child => {
return typeof child === "string" ? t(child) : child;
})
}));
Live Example:
const {useState} = React;
function t(english) {
// Just so we can see that it happens
return english.toLocaleUpperCase();
}
const CustomersTable = () => {
var headers=<React.Fragment>
<th>Name</th>
<th>Age</th>
<th>Another text</th>
</React.Fragment>;
return <Table
headers={headers}
/>;
};
const Table = ({headers}) => {
const clonedHeaders = React.Children
.toArray(headers.props.children)
.map(header => React.cloneElement(header, {
className: "text-gray-900 py-3 font-light text-xs",
children: React.Children.toArray(header.props.children).map(child => {
return typeof child === "string" ? t(child) : child;
})
}));
return <table>
<thead>
<tr>
{clonedHeaders}
</tr>
</thead>
</table>;
};
ReactDOM.render(<CustomersTable />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
That example doesn't do any recursion, so it won't handle <th><span className="something">Name</span></th>. If you want to handle that, you'll have to write a recursive function to handle it, but it'll be along the same lines.

How to filter through a table with React?

I am trying to filter through an array so that when a certain tab is clicked, only those results show. I have managed to isolate the certain variables I want to remain but the others that don't fit the criteria still remain. How do I get the filter method to actually render on the page so that the results can be shown. I have searched for hours for and have tried to get the tbody and sort through that but I just get confused as I am mostly new to javascript and react. Can someone point me in the right direction?
Filter Method
const tbody = document.getElementsByTagName('tbody')
console.log(tbody)
//change active class
function addTabBackground() {
const tabs = document.querySelectorAll('[data-tab]')
window.onload = function () {
tabs.forEach(tab => {
tab.addEventListener('click', () => {
if (tab.getAttribute('data-tab') === 'gains') {
listOfOptions.map(option => {
console.log(option.totalProfit)
})
}
tabs.forEach(tab => {
tab.classList.remove('active')
})
tab.classList.add('active')
})
})
}
}
<div className="outputs" >
<table>
<thead>
<tr>
<th>Date</th>
<th>Stock Name</th>
<th>Price Of Option</th>
<th>Number Of Options</th>
<th>Total Amount Spent</th>
<th>Option Sold At</th>
<th>Amount Of Options Sold</th>
<th>Proft</th>
</tr>
</thead>
{listOfOptions.map(option => {
return (
<tbody>
<tr>
<td>{option.clock}</td>
<td>{option.name.toUpperCase()}</td>
<td>${option.price}</td>
<td>{option.amountOfOptions}</td>
<td>${option.totalAmountSpent.toFixed(2)}</td>
<td>${option.optionPriceSoldAt}</td>
<td>{option.amountOfOptionsSold}</td>
<td style={{ color: option.totalProfit >= 0 ? 'green' : 'red' }}>${option.totalProfit.toFixed(2)}</td>
</tr>
</tbody>
)
})}
</table>
</div>
I have used React-Bootstrap-v5 to get Nav, Nav.Item with eventKey and then passed selectedKey in its onSelect function to change the tabs.
Then once we get the data inside my data variable, I used the map function to go over the array. Inside Map Function I have used the required condition to filter the elements i.e. variable = 'Open' or 'Live'.
This will only show the Open type in Open Tab and Live Type Data inside Live Tab.
Hope it's clear to you.
import React, { useEffect, useState } from 'react';
const TestSeries = () => {
// Declare Variable for data to be fetched from API
const [data, setData] = useState([]);
const fetchTestData = async () => {
const response = await axios.get(site_ip + '/apiLink');
setData(response.data.Content);
};
useEffect(() => {
fetchTestData();
}, []);
// State Variable to keep track of active tab
const [activeTab, setActiveTab] = useState('Open');
return (
<>
<Nav
activeKey={activeTab}
fill
variant="pills"
onSelect={(selectedKey) => {
setActiveTab(selectedKey);
}}
>
<Nav.Item>
<Nav.Link eventKey="Open">Open</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="Live">Live</Nav.Link>
</Nav.Item>
</Nav>
<br />
<Table striped bordered hover>
<thead>
<tr>
<th>#</th>
<th>Column1</th>
<th>Column2</th
<th>Column3</th>
<th>Column4</th>
<th>Data Type</th>
</tr>
</thead>
<tbody>
{data.map((item, index) =>
// Condition by which data will be filtered
item.data_type == activeTab ? (
<tr>
<td>{index + 1}</td>
<td>{item.col1}</td>
<td>{item.col2}</td>
<td>{item.col3} </td>
<td>{item.col4}</td>
<td>{item.data_type}</td>
</tr>
) : null
)}
</tbody>
</Table>
</>
);
};
export default TestSeries;
Result
Assuming from the comment that you have something vaguely looking like:
function Page() {
return (
<>
<Navbar />
<Table />
</>
)
}
What you need to do is to store the current tab in a state, and pass this state down to the Table component so that you can use a Array.filter when rendering your table.
function Page() {
const [activeTab, setActiveTab] = useState(DEFAULT_ACTIVE_TAB)
return (
<>
<Navbar activeTab={activeTab} setActiveTab={setActiveTab} />
<Table activeTab={activeTab} />
</>
)
}
Your Navbar component should have a onClick handler where it is calling the setActiveTab function when the active tab change.
Then in your Table component you should have something like this:
function Table({ activeTab }) {
return (
<table>
...
{listOfOptions
.filter(option => /* something depending on the activeTab */)
.map(option => <... />)
}
</table>
}

Display JSON child content to HTML table in Reactjs

Guys i know this already asked many times, but i still don't get how to solve my problem. So what i want to do is display some nested JSON data to HTML table.
So this is the JSON i fetch.
and this is my reactjs code:
var [infectionData, setInfectionData] = useState({
response: []
});
var [isLoaded, setLoaded] = useState(false);
useEffect(() => {
var fetchData = async () => {
var url = "https://api.covid19api.com/summary";
var result = await axios.get(url);
var response = result.data
response = Array(response);
setInfectionData({ response: response });
console.log(infectionData.response);
}
fetchData();
setLoaded(true);
});
and this is the HTML table:
<Table bordered hover className="mt-3 w-75">
<thead>
<tr>
<th>Country</th>
<th>Total Infection</th>
<th>New Deaths</th>
</tr>
</thead>
<tbody>
{
infectionData.response.Countries.map((item) => (
<tr>
<td>{item.Country}</td>
<td>{item.TotalConfirmed}</td>
<td>{item.NewDeaths}</td>
</tr>
))
}
</tbody>
</Table>
Any idea how to solve this ?
Here are the Array constructor https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Array
response = Array(response); remove this line and everything will be good.
Or
infectionData.response[0].Countries.map((item) => (
<tr>
<td>{item.Country}</td>
<td>{item.TotalConfirmed}</td>
<td>{item.NewDeaths}</td>
</tr>
))
You may try with this
infectionData.response.Countries && infectionData.response[0].Countries.map((item) => (
<tr>
<td>{item.Country}</td>
<td>{item.TotalConfirmed}</td>
<td>{item.NewDeaths}</td>
</tr>
))

Categories