How to pass a nested array in ReactTable getTrProps - javascript

I have a nested array for customers indicating whether they have paid for services offered. Am using ReactTable to display the data. I would like if customers have paid, the row with the customer that has paid to be highlighed in Yellow. Currently am getting the TypeError: Cannot read properties of undefined (reading 'status').
How can i improve the code below in order to correct the error status is undefined. Thanks in advance
Json Output
[{
"customers": {
"_id": "63e9303a16267390f9304321",
"customerdetails": "63e6a4d21aeb535a4fe1b841",
"status": "Paid",
"amountPaid": "500",
"roomNo": "2",
"servedby": "Wade Jones",
"createdAt": "2023-02-12T18:30:18.756Z",
"updatedAt": "2023-02-12T18:30:18.756Z",
"__v": 0
}
}]
ReactTable code
<ReactTable
getTrProps = {(state, rowInfo, instance) => {
if (rowInfo) {
return {
style: {
background: rowInfo
? rowInfo.row.customers.status === 'Paid'
? "Yellow"
: "none"
: "none"
}
};
}
return {};
}}
/>

The issue is that you are trying to access the 'status' property of an undefined object. You need to check if the 'customers' object is defined before attempting to access the 'status' property.
Change the code to the following:
<ReactTable
getTrProps = {(state, rowInfo, instance) => {
if (rowInfo && rowInfo.row.customers) {
return {
style: {
background: rowInfo.row.customers.status === 'Paid' ? "Yellow" : "none"
}
};
}
return {};
}}
/>

Related

How to use values from Formik initial values and pass them back into React Select?

I've currently implemented a means of setting my Formik initial values from an API call which is all working fine but I'm currently facing an issue with re-populating my react-select field from my initial values.
At the moment, my initial values (snippet) from API fetch call looks like this:
const emptyGroup = {
groupName: "",
groupValues: []
}
const INITIAL_FORM_STATE = {
myName: '',
allGroups: [emptyGroup]
};
"allGroups": [
{
"groupName": "Group Astro",
"groupValues": [
{
"value": "My Group A",
"label": "My Group A"
},
{
"value": "My Group B",
"label": "My Group B"
}
]
}
]
Below is my react-select component:
<ReactSelect
options={ myGroupOptions }
isMulti={true}
name={`allGroups.${index}.groupValues`}
onChange={(option) => formikProps.setFieldValue({`allGroups.${index}.groupValues`}, option.value)}
onBlur={formikProps.handleBlur}
value={ ????? }
/>
What I am unsure is, how do I feed the values from the groupValues array above back into value={ ?????? } so that when this <ReactSelect /> component is rendered, it displays the values: My Group A My Group B within it?
Just in case someone else comes across this issue/query, I managed to solve the issue as follows for value together with formik values:
<ReactSelect
options={ myGroupOptions }
isMulti={true}
name={`allGroups.${index}.groupValues`}
onChange={(option) => formikProps.setFieldValue({`allGroups.${index}.groupValues`}, option.value)}
onBlur={formikProps.handleBlur}
value={values.allGroups[index].groupValues}
/>

React render data with array index

I have facing an issue in React js, I want to render all data from rest API and show with a numeric index.
Rest API:
[
{
"id": "1",
"start_date": "2020-05-08 09:45:00",
"end_date": "2020-05-08 10:00:00",
"full_name": "mirza",
"cust_full_name": "furqan",
},
{
"id": "2",
"start_date": "2020-05-08 02:45:00",
"end_date": "2020-05-08 03:00:00",
"full_name": "mirza",
"cust_full_name": "ahmed",
},
{
"id": "3",
"start_date": "2020-05-08 06:45:00",
"end_date": "2020-05-08 07:00:00",
"full_name": "mirza",
"cust_full_name": "ali",
}
]
my code:
render()
{
let FullNameSlot1 = null //FullNameSlot
let SecondFullNameSlot1 = null
let BaberNameSlot1 = null //BaberNameSlot
let SecondBaberNameSlot1 = null
if (this.state.appointmentdata && this.state.appointmentdata.length
this.state.appointmentdata[0].start_date.toString() > this.state.newprevious
)
{
FullNameSlot1 = (
<p key={0}>{this.state.appointmentdata[0].cust_full_name}</p>
)
BaberNameSlot1 = (
<p key={0}>{this.state.appointmentdata[0].full_name}</p>
)
}
i want to render data with array {index}
if (this.state.appointmentdata && this.state.appointmentdata.length
this.state.appointmentdata[1].start_date.toString() > this.state.newprevious
)
{
SecondFullNameSlot1 = (
<p key={1}>{this.state.appointmentdata[1].cust_full_name}</p>
)
SecondBaberNameSlot1 = (
<p key={1}>{this.state.appointmentdata[1].full_name}</p>
)
}
I want to render all data from rest API and show with a numeric index. Make my code it simple.
<p key={index}>{this.state.appointmentdata[index][0].cust_full_name}</p>
<p key={index}>{this.state.appointmentdata[index][1].cust_full_name}</p>
Demo:
https://codesandbox.io/s/agitated-elion-quqp1
What should i do? Any one help me?
You can use conditional rendering and your final condition is a ternary to either map the array of data to JSX or return null. The array::map first argument is the current element being iterated, and the second argument is the current index. When returning JSX like this though you need to return a single node. Here I've used a react Fragment and attached the key there. I also destructured the element properties you wanted to display.
Conditional Rendering
Lists and Keys
{
(this.state.appointmentdata &&
this.state.appointmentdata.length &&
this.state.appointmentdata[1].start_date.toString() > this.state.newprevious)
? this.state.appointmentdata.map(({ cust_full_name, full_name }, index) => (
<Fragment key={index}>
<p>{cust_full_name}</p>
<p>{full_name}</p>
</Fragment>
) : null
}
#adnan khan Welcome to Stackoverflow! to render an array of elements you can make use of Array.map function https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
In your example it might look like this
if(this.state.appointmentdata && this.state.appointmentdata.length){
this.state.appointmentdata.map((data ,index) => <p key={index}>{data.cust_full_name}</p> )
}
If you want to render elements dynamically then conditional rendering is an option
You can use map() on appointmentdata and create the same number of elements as objects in the result of API
Sample:
render() {
return (
<React.Fragment>
{
this.state.appointmentdata.length
?
this.state.appointmentdata.map(ele => {
return (
<React.Fragment>
<p key={`cf_${ele.id}`}>{ele.cust_full_name}</p>
<p key={`f_${ele.id}`}>{ele.full_name}</p><hr/>
</React.Fragment>
)
})
: "__"
}
</React.Fragment>
);
}

Creating a function to sort table React, JSX

Im trying to figure out a way to sort my rows array depending on the sortBy and order state. I currently have a handleSort function which is grabbing the column name and setting it to sortBy state and also toggling the order by either "asc" or "desc" but now I'm trying to figure out how to manipulate the rows depending on the sortBy and order state. I believe it's possible creating a long conditional rendering but wondering does anyone one have simpler way I might be missing. Your help is appreciated thank you.
state = {
columnHeaders: [
"Meat",
"Protein (g)",
"Calories (cal)",
"Carbohydrates (g)",
"Fat (g)"
],
rows: [
["chicken breast", "25", "200", "37", "8"],
["fried chicken", "45", "450", "21", "16"],
["baked fish", "15", "250", "30", "9"]
],
sortedBy: "",
order: "desc",
query: "all",
error: false
};
handleClose = () => {
this.setState({ error: !this.state.error });
};
handleQuery = keyword => {
this.setState({
query: keyword
});
if (keyword === "chicken") {
this.setState({
rows: this.state.rows.filter(row => row[0].includes("chicken"))
});
} else if (keyword === "fish") {
this.setState({
rows: this.state.rows.filter(row => row[0].includes("fish"))
});
} else if (keyword === "beef") {
this.setState({
rows: this.state.rows.filter(row => row[0].includes("beef"))
});
} else {
this.setState({
error: true
});
}
};
handleSort = header => {
this.setState(state => ({
sortedBy: header,
order: state.sortedBy === header ? invertDirection[state.order] :
"asc"
}));
};
render() {
const { columnHeaders, rows } = this.state;
return (
<div className="App mt-3">
<AlertDialogSlide
open={this.state.error}
handleClose={this.handleClose}
/>
<Search handleQuery={this.handleQuery} />
<Paper className="mt-3">
<Header />
<Table>
<TableHead>
<TableRow>
{columnHeaders.map((header, i) => (
<TableHeader
header={header}
key={`th-${i}`}
handleSort={this.handleSort.bind(this, header)}
/>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row, i) => (
<TableRow key={`thc-${i}`}>
<TableItem row={row} />
</TableRow>
))}
</TableBody>
</Table>
</Paper>
</div>
);
}
}
First of all, you should save the original data and the filtered data in different locations - e.g. the original data comes from the props and the filtered data is in the state. Because if you overwrite the data (like you do at the moment), you won't be able to e.g. search for "fish" after you've searched for "chicken", because the data was filtered to only include "chicken"-entries - all "fish" entries where removed and are not accessible anymore.
Second, if you want to set a new state depending on an old state, you should always provide a function instead of the state object to the setState function (check out this link).
Third, instead of using the if-else blocks in handleQuery, you can just use the keyword directly to filter.
And now to your question:
You can use the following code snippet to order and filter your rows:
const { rows } = this.props; // assuming the original data comes from the props!
const { query, sortedBy, order } = this.state;
// filter the data (only if query is not "all"
const newRows = query === "all" ? rows : rows.filter(row => row[0].includes(query));
const sortedRows = sortedBy === "" ? newRows : newRows.sort((a, b) => {
const valueA = a[sortedBy]; // get the row to sort by
const valueB = b[sortedBy]; // get the row to sort by
let sortedValue = 0;
if (valueA < valueB) {
sortedValue = -1;
}
else if (valueA > valueB) {
sortedValue = 1;
}
if (order === "desc") {
sortedValue *= -1; // if descending order, turn around the sort order
}
return sortedValue;
});
this.setState({rows: sortedRows});

React native : Iterate on a JSON object without getting undefined function

I'm new to React-Native and I'm learning this by tutorials and examples all over the web. I am trying to do something very simple but it has been a week since I hit this problem and after digging StackOverflow and many other contents, none of them could help. So I decided to ask it directy. My apologies if the question looks duplicate or it seems silly.
I am trying to iterate over a JSON object and display it. All I want to do right now is to show each JSON object with its title (username). I'm planning to do much more - make the title a button and show the details of user after hitting button - but right now this is the big rock I've hit into.
Here is my code. Please note my comment on fetchdata method :
import React, { Component } from 'react'
import { View, Text, FlatList, TouchableOpacity, ListView } from 'react-native'
class MyListItem extends React.PureComponent {
_onPress = () => {
this.props.onPressItem(this.props.id);
};
render() {
const textColor = this.props.selected ? "red" : "black";
return (
<TouchableOpacity onPress={this._onPress}>
<View>
<Text style={{ color: textColor }}>
{this.props.title}
</Text>
</View>
</TouchableOpacity>
);
}
}
export default class HttpExample extends Component {
constructor(props) {
super(props);
this.state = {
data: '',
username: [],
first_name: '',
last_name: ''
};
//Using ES6 we need to bind methods to access 'this'
this.fetchData = this.fetchData.bind(this);
}
componentDidMount() {
this.fetchData();
}
fetchData() {
// The first line - which is commented - returns all of non-admin
// users, the second one returns only one user. Note that the
// second one works fine and the first one does not.
// fetch('http://URL/users.json', {
fetch('http://URL/users/12345678001.json', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
data: responseJson,
username: responseJson.username,
first_name: responseJson.first_name,
last_name: responseJson.last_name
})
})
.catch((error) => {
console.error(error);
});
}
_keyExtractor = (item, index) => item.id;
_onPressItem = (id: string) => {
// updater functions are preferred for transactional updates
this.setState((state) => {
// copy the map rather than modifying state.
const selected = new Map(state.selected);
selected.set(id, !selected.get(id)); // toggle
return {selected};
});
};
_renderItem = ({item}) => (
<MyListItem
id={item}
onPressItem={this._onPressItem}
title={this.state.username}
/>
);
render() {
return (
<FlatList
data={[this.state.data]}
renderItem={this._renderItem}
/>
)
}
}
And here is a sample of one of my JSON objects created by Django ReST framework, written by myself. I've just simplified the object a bit and removed some of the fields, for better reading (The avatar field is a base64 image field and it is much smaller than the original one):
{
"username": "12345678003",
"email" : "sample#gmail.com",
"first_name": "AAA",
"last_name": "BBB",
"phone_number": "12045678000",
"gender": "M",
"city": "NY",
"description": "",
"date_of_birth": "2010-03-28",
"avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAPBhAREQ8QDQ8PDxIWEBAWFRANDxAQFRUWFhURExUYHSggGBolGxUTITEhJSkrLi4uFx8zODMsNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOEA4QMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABAUBAgMGB//EADIQAQABAwEHAQYEBwAAAAAAAAABAgMRBAUSITFBUXFhIjKRobHBM4HR8RMjQmJyguH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APpgCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIAAAAAAAAAAAAAAAAAAAAAAANrduaq8RGZkGqVY0FdXON2PXn8E/SaOKIzPGrv0jwlAhW9nURHHNU/B3p0tER7sOwDjVpaJj3YcbmzqJjhmJTAFPf0FdPGPaj5/BEejRtV",
"groups": [1,2],
"user_permissions": [],
"interests": [1,2]
}
The above is what I get by calling http://URL/users/12345678001.json which returns one user. I have been able to show the user as one touchable opacity in the application (the above code works) But when I call users.json which has a structure like below:
[{user1 data},{user2 data}, etc.]
I cannot make the mobile application display each user's username in the mobile output. Either I get nothing (nothing is displayed) or the usual errors pop up (TypeError: object is not a function, etc.) I want to have the application iterate through the whole users.json and show each user's username as one touchable opacity. I've tried using .map which throws me the error, or calling each object in responseJson by their array index which either shows me nothing or throws error.
Let me know about your ideas and solutions.
FYI, I am testing this on my Nexus 5X phone directly.
Update
Here is an example of users.json as it reflects in my console log :
[{
"username": "12345678001",
"email" : "sample#gmail.com",
"first_name": "AAA",
"last_name": "BBB",
"phone_number": "12045678000",
"gender": "M",
"city": "NY",
"description": "",
"date_of_birth": "2010-03-28",
"avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAPBhAREQ8QDQ8PDxIWEBAWFRANDxAQFRUWFhURExUYHSggGBolGxUTITEhJSkrLi4uFx8zODMsNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOEA4QMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABAUBAgMGB//EADIQAQABAwEHAQYEBwAAAAAAAAABAgMRBAUSITFBUXFhIjKRobHBM4HR8RMjQmJyguH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APpgCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIAAAAAAAAAAAAAAAAAAAAAAANrduaq8RGZkGqVY0FdXON2PXn8E/SaOKIzPGrv0jwlAhW9nURHHNU/B3p0tER7sOwDjVpaJj3YcbmzqJjhmJTAFPf0FdPGPaj5/BEejRtV",
"groups": [1,2],
"user_permissions": [],
"interests": [1,2]
},
{
"username": "12345678003",
"email" : "sample#gmail.com",
"first_name": "AAA",
"last_name": "BBB",
"phone_number": "12045678003",
"gender": "M",
"city": "NY",
"description": "",
"date_of_birth": "2010-12-20",
"avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAPBhAREQ8QDQ8PDxIWEBAWFRANDxAQFRUWFhURExUYHSggGBolGxUTITEhJSkrLi4uFx8zODMsNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOEA4QMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABAUBAgMGB//EADIQAQABAwEHAQYEBwAAAAAAAAABAgMRBAUSITFBUXFhIjKRobHBM4HR8RMjQmJyguH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APpgCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIAAAAAAAAAAAAAAAAAAAAAAANrduaq8RGZkGqVY0FdXON2PXn8E/SaOKIzPGrv0jwlAhW9nURHHNU/B3p0tER7sOwDjVpaJj3YcbmzqJjhmJTAFPf0FdPGPaj5/BEejRtV",
"groups": [1,2],
"user_permissions": [],
"interests": [1,2]
}]
Another Update
As requested, here is a screenshot of my console, note that it differs from what I've posted here and has many different fields :
More Investigation:
I decided to make the code much simpler, and just focus on the main problem. How to return the iterated object for display:
My code is now this:
import React, { Component } from 'react'
import { View, Text, ListView } from 'react-native'
export default class HttpExample extends Component {
constructor(props) {
super(props);
data = [''];
}
fetchData() {
fetch('http://URL/users.json', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log("ResponseJson is :" + responseJson);
console.log(responseJson.users.length);
console.log(responseJson.users.username);
console.log(responseJson.users);
console.log("THIS:::" + responseJson.users[0].username);
responseJson.users.map((user) =>
{
console.log("THIS:::" + user.username);
data.push(user.username);
console.log("This.data:" + data[0] + "second:" + data[1]);
});
return data;
})
.catch((error) => {
console.error(error);
});
}
_keyExtractor = (item, index) => item.id;
render() {
return (
<View>
<ListView
dataSource={this.fetchData()}
renderRow={(data) => <Text>{data.username}</Text>}
/>
</View>
)
}
}
All of the "console.log" commands return with correct info (Check the end of the post), but my render does not work and throws undefined is not a object. I really don't understand what is the exact problem? isn't data an array? Why it can't be displayed and throws TypeError? What am I getting wrong?
console.log outputs, in correct order :
ResponseJson is :[object Object]
3
undefined
(whole users.json is returned)
THIS:::12345678001
THIS:::12345678001
This.data:second:12345678001
THIS:::12345678002
This.data:second:12345678001
THIS:::12345678003
This.data:second:12345678001

(React Native) Retrieving next value in JSON file when button is pressed

Let's say I have a local JSON file (./movies.json) structured as
{ "movies": [
{ "title" : "Terminator", "year" : "1984", "genre" : "Action" },
{ "title" : "Jumanji", "year" : "2017", "genre" : "Adventure"},
 { "title" : "Incredibles 2", "year" : "2017", "genre" : "Animation"}]
}
Whenever a button is clicked, I want to output, for example, a Text Field with
Terminator --> Jumanji --> Incredibles 2, in order.
I also want to be able to access all three of "title", "movie", "genre" (in separate text fields) in order, when the button is clicked.
This is what I have so far, to get just the titles of the movies in order.It doesn't work, because I don't think I'm pulling from the JSON file correctly.
import jsonData from "./movies.json";
export default class Movies extends React.Component {
constructor(props) {
super(props);
this.state = {
results:{
titles: [],
years: [],
genres: []
}
}
};
}
componentDidMount = () => {
// const data = json.stringify(jsonData) I think this line is not correct
this.setState({ data })
}
render () {
titles_list = this.state.results.titles.map((item) => {
return (
<View key={item.title}>
<Text>
{item.title}
</Text>
</View>
);
});
return (
<View>
{titles_list}
</View>
);
}
}
I'm not sure how to implement a button so that when it is pressed, the next title/year/genre is shown. Help would be appreciated. Thanks!
Store the index of the array in a state variable.
First of all, I will assume that you passed that json into state.movies
So initialize it as follows:
this.state = {
movies: [], // where the movies are
displayIndex: 0 // This will be the index that you show
}
When you press your button call a function that will call either of the following functions:
moveForward(){
this.setState({displayIndex: this.state.displayIndex++})
}
moveBack(){
this.setState({displayIndex: this.state.displayIndex--})
}
Then when you display the fields under your render function grab the object you need as follows:
render(){
const movieData = this.state.movies[this.state.displayIndex];
....//Do the display logic here

Categories