I want to run a filter method on the renderTable method that I've defined below. Is it possible to do:
renderTable().filter(x => x.name)?
Right now, I have a table with rows of each category and their results from a url that provided some json data.
I would like to make a feature that allows users to adjust the setting to return their desired results.
CODE
const renderTable = () => {
return players.map(player => {
return (
<tr>
<td>{player.name}</td>
<td>{player.age}</td>
<td>{player.gender}</td>
<td>{player.state}</td>
<td>{player.status}</td>
</tr>
)
})
}
return (
<div className = "App">
<h1>Players</h1>
<table id = "players">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Gender</th>
<th>State</th>
<th>Status</th>
</tr>
</thead>
<tbody>{renderTable()}</tbody>
</table>
</div>
);
You can apply the filter before the map. Here, give this a try:
const renderTable = () => {
return players
.filter(player => player.state === "NSW")
.map(player => {
return (
<tr>
<td>{player.name}</td>
<td>{player.age}</td>
<td>{player.gender}</td>
<td>{player.state}</td>
<td>{player.status}</td>
</tr>
);
});
};
Here's a Working Sample CodeSandbox for your ref.
Yes you can. Just filter before map players.filters(...).map. But this is better
const renderTable = () => {
const rows = []
players.forEach((player, index) => {
if(player.name) {
rows.push(
<tr key={index}>
<td>{player.name}</td>
<td>{player.age}</td>
<td>{player.gender}</td>
<td>{player.state}</td>
<td>{player.status}</td>
</tr>
)
}
})
return rows;
}
Related
I am creating a table dynamically in React with the API response as it is as it receives.
data = {"name":"tom", "age":23, "group":null, "phone":xxx}
It is working fine with that, but the group key sometimes contains another object, so I want to create a sub-table whenever there is another object inside a key.
For example:
data = {"name":"tom", "age":23, "group":{"id":123, "joined_at":12-jan-2022}, "phone":xxx}
My current code is:
<table>
{Object.keys(data).map(index=> (
<tr>
<td>{index}</td>
<td>{data[index]?.toString()}</td>
</tr>
))}
</table>
The code you have shared would change as follows:
<table>
{Object.keys(data).map((item, index) => {
if (group) {
return (
<>
<tr>
<td>{index}</td>
<td>{item.toString()}</td>
</tr>
<tr>
<table>
<tr>
<td>{group.id}</td>
<td>{group.joined_at}</td>
</tr>
</table>
</tr>
</>
);
}
return (
<tr>
<td>{index}</td>
<td>{item.toString()}</td>
</tr>
);
})}
</table>;
You can fix the formatting as per your needs but this is essentially how you would create a sub-table based on the value of group
A slightly improved version would be :
const normalTableRow = (index, item) => {
return (
<tr>
<td>{index}</td>
<td>{item.toString()}</td>
</tr>
);
};
<table>
{Object.keys(data).map((item, index) => {
if (group) {
return (
<>
{normalTableRow(index, item)}
<tr>
<table>
<tr>
<td>{group.id}</td>
<td>{group.joined_at}</td>
</tr>
</table>
</tr>
</>
);
}
return normalTableRow(index, item);
})}
</table>;
EDIT: updating solution based on comment
const normalTableRow = (index, item) => {
return (
<tr>
<td>{index}</td>
<td>{item.toString()}</td>
</tr>
);
};
const isObject = (value) => {
return typeof value === 'object' && !Array.isArray(value) && value !== null;
};
<table>
{Object.keys(data).map((item, index) => {
let subTables = Object.keys(item).map((key) => {
if (isObject(item[key])) {
return (
<tr>
<table>
<tr>
{Object.keys(item[key]).map((subKey) => {
return <td>{item[key][subKey]}</td>;
})}
</tr>
</table>
</tr>
);
}
});
return (
<>
{normalTableRow(index, item)}
{[...subTables]}
</>
);
})}
</table>;
Calling an API i get this data
{
"count":33,
"results":
[
{"id":365,"firstName":"Maisha","lastName":"Rawlings"},
{"id":613,"firstName":"Lettie","lastName":"Epps"},
{"id":433,"firstName":"Rocco","lastName":"Gant"},
{"id":856,"firstName":"Tova","lastName":"Coyle"},
{"id":896,"firstName":"Tari","lastName":"Mancuso"},
{"id":79,"firstName":"Tora","lastName":"Prince"},
{"id":59,"firstName":"Lashon","lastName":"Dunaway"},
{"id":378,"firstName":"Corey","lastName":"Schaffer"},
{"id":33,"firstName":"Nanci","lastName":"Middleton"},
{"id":390,"firstName":"Carmon","lastName":"Lavender"}
]
}
Which i have it in here for testing purposes
https://mocki.io/v1/d676e413-6659-4410-a8a3-7d5636f4b719
I have the next app made in React
const USERS_URL = "https://mocki.io/v1/d676e413-6659-4410-a8a3-7d5636f4b719";
export default function Table() {
const [names, setNames] = useState([]);
useEffect(() => {
async function getData() {
let response = await fetch(`${USERS_URL}`);
response = await response.json();
console.log(response);
setNames(response);
}
getData();
}, []);
return (
<div>
<table className="table">
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody>
{
names
&&
Object.entries(names).map(([key, value, idx]) => {
return <tr key={key}>
<td>{names.key}</td>
<td>{value.results[key]}</td>
{console.log(key, value)}
</tr>
})
}
</tbody>
</table>
</div>
);
}
I can't find the way to loop over "results", which is an array of objects. Any hint please?
Sollution
names.results.map((val,index)=>{
console.log("object",val)
})
us hte . we can access the properties inside and Object first access the result array in the object and then map() on it
I'm trying to make a table with api data searchable. I'm on my way, but unsure on how to proceed further.
Code looks like this:
const [searchTerm, setSearchTerm] = useState("");
const [searchResults, setSearchResults] = useState([]);
const handleChange = event => {
setSearchTerm(event.target.value);
};
useEffect(() => {
const results = apiData.filter(person =>
person.toLowerCase().includes(searchTerm)
);
setSearchResults(results);
}, [searchTerm]);
const renderPerson = (contact, index) => {
return (
<tr key={index}>
<td>{contact.ID}</td>
<td>{contact.Info.Name}</td>
<td>{contact.InfoID}</td>
<td>{contact.Info.DefaultEmail.EmailAddress}</td>
<td>{contact.Info.DefaultPhone.Number}</td>
<td>{contact.Info.InvoiceAddress.AddressLine1}</td>
</tr>
)
}
return (
<Fragment>
<input type="text" value={searchTerm} onChange={handleChange} placeholder="Søk.."></input>
<table id="myTable">
<thead>
<tr className="header">
<th>ID</th>
<th>Navn</th>
<th>Info Id</th>
<th>E-post</th>
<th>Telefon</th>
<th>Adresse</th>
</tr>
</thead>
<tbody>
{apiData.map(renderPerson)}
</tbody>
</table>
</Fragment>
)
https://dev.to/asimdahall/simple-search-form-in-react-using-hooks-42pg
I've followed this guide, but since I have the renderPerson function, I'm a bit unsure on how to handle this.
Question: Is there any way to get this working, or am I approaching it the wrong way? I'm aware that I need to put searchResult in the tbody somehow, but then the table won't be populated.
Any help is much appreciated
Edit: displaying code for getting apiData:
useEffect(() => {
getContacts()
}, [])
const getContacts = () => {
$.ajax({
url: `http://localhost:5000/getContacts`,
type: "POST",
data: ajaxObj,
success: (data) => {
let response = JSON.parse(data)
setApiData(response)
setLoading(false)
},
error: () => {
console.log("noe feilet?");
}
});
}
console.log(apiData)
Data looks like this:
data
Change apiData to searchResults on render
<tbody>
{searchResults.map(renderPerson)}
</tbody>
Change your filter way result (Updated)
const results = apiData.filter(person =>
person.Info.Name.toLowerCase().includes(searchTerm)
);
....
const renderPerson = (item, index) => {
return (
<tr key={index}>
<td>{item.ID}</td>
<td>{item.Info.Name}</td>
<td>{item.InfoID}</td>
<td>{item.Info.DefaultEmail.EmailAddress}</td>
<td>{item.Info.DefaultPhone.Number}</td>
<td>{item.Info.InvoiceAddress.AddressLine1}</td>
</tr>
)
}
Try this
export default function () {
const [searchTerm, setSearchTerm] = useState("");
const [searchResults, setSearchResults] = useState([]);
const apiData=[
{
ID:'1222',
Info:{
ID:'1222',
EmailAddress:'test#test.com',
Number:'2222222222',
AddressLine1:'test'
}
},
{
ID:'2333',
Info:{
ID:'2333',
EmailAddress:'test2#test.com',
Number:'1111111111',
AddressLine1:'test2'
}
}
]
const handleChange = event => {
setSearchTerm(event.target.value);
if(event.target.value){
const results = apiData.filter(person =>
person.ID.toLowerCase().includes(event.target.value)
);
setSearchResults(results);
}else{
setSearchResults([]);
}
};
const renderPerson = (contact, index) => {
return (
<tr key={index}>
<td>{contact.ID}</td>
<td>{contact.Info.Name}</td>
<td>{contact.Info.ID}</td>
<td>{contact.Info.EmailAddress}</td>
<td>{contact.Info.Number}</td>
<td>{contact.Info.AddressLine1}</td>
</tr>
)
}
return (
<Fragment>
<input type="text" value={searchTerm} onChange={handleChange} placeholder="Søk.."></input>
<table id="myTable">
<thead>
<tr className="header">
<th>ID</th>
<th>Navn</th>
<th>Info Id</th>
<th>E-post</th>
<th>Telefon</th>
<th>Adresse</th>
</tr>
</thead>
<tbody>
{searchResults.map(renderPerson)}
</tbody>
</table>
</Fragment>
)
}
So I've got this table in React. It works fine with all the columns except the one with the country name. I checked API so className definitely matches with it and I am a bit clueless how to fix it.
const Table = () => {
const[country, setCountry] = useState([]);
const[toggle, setToggle] = useState(true);
const sortColumnNumber = (sort, columnName, data) => {
data = data.sort((a, b) => {
return sort ? b[columnName] - a[columnName] : a[columnName] - b[columnName];
});
}
useEffect(() => {
const loadData = async() => {
await fetch('https://api.covid19api.com/summary')
.then(response => response.json())
.then(data => {
const stats = data.Countries;
sortColumnNumber(toggle, 'TotalConfirmed', stats)
setCountry(stats);
})
}
loadData();
}, []);
return(
<React.Fragment>
<table className="table table-bordered table-stripped">
<thead >
<tr onClick={(e) =>{
setToggle(!toggle);
sortColumnNumber(toggle, e.target.className, country);
}} style={{cursor: "pointer"}} className="thead-dark">
<th className="Country" scope="col">Country</th>
<th className="TotalConfirmed" scope="col">Total Cases</th>
<th className="NewConfirmed" scope="col">New Cases</th>
<th className="NewDeaths" scope="col">New Deaths</th>
<th className="TotalDeaths" scope="col">Total Deaths </th>
<th className="TotalRecovered" scope="col">Total Recovered </th>
</tr>
</thead>
<tbody>
<CountryStats country={country} />
</tbody>
</table>
</React.Fragment>
)
}
Try something like that:
const sortColumnNumber = (sort, columnName, data) => {
data = data.sort((a, b) => {
let [first, second] = sort ? [a, b] : [b, a];
if (first[columnName] < second[columnName]) return -1;
if (first[columnName] > second[columnName]) return 1;
return 0;
});
};
It's important to return -1 or 0 or 1 to avoid problem with data types.
See more about sort method in this link: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
It doesn't work with country name because it is a String type and your callback method logic will not work for sorting Strings.
Subtracting two String values results in NaN.
Refer to this SO answer for sorting Strings.
I am trying to parse the data dynamically for the table. So far I have tried the following to display the table.
renderTableData = () => {
return this.props.data.map((item, index) => {
const { name, value } = item;
return (
<tr key={index}>
<td>{name}</td>
<td>{value}</td>
</tr>
);
});
};
Here I am hardcoding the field values for displaying. I need this to be dynamic
Full code: https://codesandbox.io/s/react-basic-class-component-3kpp5?file=/src/Table.js:0-805
import * as React from "react";
class Table extends React.Component {
renderTableData = () => {
return this.props.data.map((item, index) => {
const { name, value } = item;
return (
<tr key={index}>
<td>{name}</td>
<td>{value}</td>
</tr>
);
});
};
renderTableHeader = () => {
let header = Object.keys(this.props.data[0]);
return header.map((key, index) => {
return <th key={index}>{key.toUpperCase()}</th>;
});
};
render() {
return (
<div>
<table>
<tbody>
<tr>{this.renderTableHeader()}</tr>
{this.renderTableData()}
</tbody>
</table>
</div>
);
}
}
export default Table;
You can loop through object properties with Object.entries
renderTableData = () => {
return this.props.data.map((item, index) => {
return (
<tr key={index}>
{Object.entries(item).map(([key, value])=> <td key={key}>{value}</td>)}
</tr>
);
});
};
However, as you can see you lost control of the order of columns. Additionaly there might be columns you don't wish to display.
You can tackle that by appending Object.entries with custom implemented functions
<tr key={index}>
{Object.entries(item)
.filter(predicateFunction)
.sort(sortingFunction).map(([key, value])=> <td key={key}>{value}</td>)}
</tr>
Or switch to react-data-table