ReactJS Add new row to Table - reactjs

I create Table dynamicaly:
In component Table I set the default values of table in json:
constructor(props) {
super(props);
this.state = {
data: [
{'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': ''}
]
};
}
Then use it to render table:
render() {
return (
<div className={styles}>
<table>
<thead>
<tr>{this.getHeader()}</tr>
</thead>
<tbody>
{this.getRowsData()}
</tbody>
<button onClick={this.addRow}>
Add new row
</button>
</table>
</div>
);
}
This is a methods realization:
getKeys = function () {
return Object.keys(this.state.data[0]);
};
getHeader = function () {
var keys = this.getKeys();
return keys.map((key, index) => {
return <th key={key}>{key.toLowerCase()}</th>
})
};
getRowsData = function () {
var items = this.state.data;
var keys = this.getKeys();
return items.map((row, index) => {
return <tr key={index}><RenderRow key={index} data={row} keys={keys}/></tr>
})
};
And now I try to add new row, using this method:
addRow = function () {
let newRows = this.state.data.push({'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': ''});
this.setState({data: newRows});
};
But when I try it, I receive the following error: TypeError: Cannot convert undefined or null to object
in
return Object.keys(this.state.data[0]);
Indeed, after I push a new object to "data", I see, that "data" not containts any elements. Although before that it contained 1 element: {'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': ''}

This is the wrong in your function. Push will return you the values that pushed into the array,
addRow = () => {
let existingRows = this.state.data;
existingRows.push({'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': ''});
this.setState({ data: existingRows });
};
If You wish to use arrow function for addRow the below will not be needed! Or if you wish to use the normal function you are using you have to change the button onClick as below,
addRow = function () {
let existingRows = this.state.data;
existingRows.push({ 'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': '' });
this.setState({ data: existingRows });
};
<button onClick={() => this.addRow()}>
Add new row
</button>

The value of newRows will be {'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': ''} which you are setting as state instead it should be an array.
So what you can do is:-
let rowsData = this.state.data;
existingRows.push({ 'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': '' });
this.setState({ data: rowsData });

Related

How to set initial state dynamically?

My initial state varies depending on how many items I get from the API call.
So basically sometimes it looks like this:
class MyComponent extends Component {
state = {
activeItem0: '',
activeItem1: '',
activeItem2: '',
activeItem3: '',
}
...
and some times it might look like this depending on the data returned by the database.
class MyComponent extends Component {
state = {
activeItem0: '',
activeItem1: '',
activeItem2: '',
activeItem3: '',
activeItem4: '',
activeItem5: '',
}
...
Is there a way to set the initial state keys dynamically?
here's what I have so far:
class MyComponent extends Component {
state = {
activeItem0: '',
activeItem1: '',
activeItem2: '',
activeItem3: ''
}
// Set the value for each product on the store
handleItemClick = (e, { name, children }) => this.setState({[e.target.name]: children })
let buttonGroup = _.times(products.length, i => (
<Button.Group>
<Button
name={`activeItem${i}`}
active={this.state[`activeItem${i}`] === 'Val1'}
onClick={this.handleItemClick}
>
Val1
</Button>
<Button
name={`activeItem${i}`}
active={this.state[`activeItem${i}`] === 'Val2'}
onClick={this.handleItemClick}>
Val2
</Button>
<Button
name={`activeItem${i}`}
active={this.state[`activeItem${i}`] === 'Val3'}
onClick={this.handleItemClick}>
Val3
</Button>
</Button.Group>
)
render() {
return(
<div>
<Grid container>{selectSizeInSideBar}</Grid>
</div>
)
}
}
So the issue is that if products.length returned by the DatabBase is 4
I should have in my initial state like this
state = {
activeItem0: '',
activeItem1: '',
activeItem2: '',
activeItem3: ''
}
but if my products.length returned by the DatabBase is 6 then
my initial state should look like this:
state = {
activeItem0: '',
activeItem1: '',
activeItem2: '',
activeItem3: ''
activeItem4: ''
activeItem5: ''
}
You can make a method that initialize your state after your component is ready ( let's say the data of your API has been received ), so its preferrable to make this in the componentDidMount.
const initializeStateForKeys = ( products ) => {
const fakeState = {};
_.each( products, product => {
fakeState[ product.id ] = { id: product.id ,isActive: product.isActive }
} );
return fakeState
}
and you should use it like this:
componentDidMount(){
API.fetchMyProducts()
.then( response => {
this.setState( { products: response.data.products }
, () => {
this.initializeStateForKeys( this.state.products);
});
});
}

Pass state to page on form submit?

I have a state on one page, and when i submit a form I'd like to redirect to another page with the state of the source page, and populate the state on the new page with the old state on the old page haha if that makes sense. Hopefully my code attempt can explain it better.
class NewFormDetails extends Component {
constructor(props) {
super(props);
this.state = {
language: this.props.language,
siteName: '',
counties: '',
siteAddress: '',
siteEmail: '',
siteNumber: '',
siteCat: '',
openTimes: '',
fees: '',
access: '',
gps: '',
w3w: '',
txtHeader: '',
txtContent: '',
isLoading: false
};
}
validateForm() {
if (this.state.siteName != '' &&
this.state.siteAddress != '' &&
this.state.siteEmail != '' &&
this.state.siteNumber != '' &&
this.state.openTimes != '' &&
this.state.fees != '' &&
this.state.access != '' &&
this.state.gps != '' &&
this.state.w3w != '' &&
this.state.txtHeader != '' &&
this.state.txtContent != '') {
return true;
} else {
return false;
}
}
handleChange = e => {
this.setState({ ...this.state, [e.target.name]: e.target.value });
console.log(this.state);
}
handleSubmit = event => {
event.preventDefault();
/* try {
await this.createSiteDetails({
siteName: this.state.siteName,
siteAddress: this.state.siteAddress,
siteCounty: this.state.counties,
siteNumber: this.state.siteNumber,
siteEmail: this.state.siteEmail,
siteCategory: this.state.siteCat,
siteOpeningTimes: this.state.openTimes,
siteFees: this.state.fees,
siteAccess: this.state.access,
siteGPS: this.state.gps,
siteW3W: this.state.w3w,
siteHeaderText: this.state.txtHeader,
siteContentText: this.state.txtContent
});
this.props.history.push("/");
} catch (e) {
alert(e);
this.setState({ isLoading: false });
} */
console.log(this.state);
this.props.history.push({
pathname:"/newSite/tours",
state:{
value: this.state
}
});
}
And here is the page i redirect to and attempt to get the state from the other page
class NewFormTours extends Component {
constructor(props) {
super(props);
this.state = {
language: this.props.language,
tourName: '',
waypoints: '',
duration: '',
toursTxtHeader: '',
toursTxtContent: '',
siteName: this.siteName,
counties: this.props.counties,
siteAddress: this.props.siteAddress,
siteEmail: this.props.siteEmail,
siteNumber: this.props.siteNumber,
siteCat: this.props.siteCat,
openTimes: this.props.openTimes,
fees: this.props.fees,
access: this.props.access,
gps: this.props.gps,
w3w: this.props.w3w,
detailsTxtHeader: this.props.detailsTxtHeader,
detailsTxtContent: this.props.detailsTxtContent,
};
You can use react router to pass data to new component.
Below discussion should be helpful.
How do i pass state through React_router?

invalid Invalid left-hand side in arrow function parameters (43:13)

hello im a noob in react and am trying to pass the car.id using props to my editcar component so i can update it via firebase , however im getting a an error Invalid left-hand side in arrow function parameters (43:13) any idea how i can pass the car.id to edit function? thanks for the help!
admin_cars.js
<ul className="TaskList">
{
Cars.map(car => (
<tr>
<th scope="row">{car.id}</th>
<td>{car.year}</td>
<td>{car.make}</td>
<td>{car.model}</td>
<td>{car.body_type}</td>
<td>{car.int_color}</td>
<td><img src={car.link} height="92" /> </td>
<td>{car.price}</td>
<td>{car.status ? "Available" : "Sold"}</td>
<td>
<Link to={`/admin/editcar/${this.props.car.id}`}>
<Icon icon={pencil} />
</Link>
</td>
</tr>
))
}
</ul>
edit_car.js
import { CarsRef, timeRef } from './reference';
class EditCar extends Component {
state = {
year: '',
make: '',
model: '',
trim: '',
engine: '',
drive_type: '',
body_type: '',
ext_color: '',
int_color: '',
transmission: '',
price: 0,
sale: 0,
status: true,
vin: '',
link: '',
elect_stab: '',
wireless: '',
seat: '',
keyless: '',
trip_comp: '',
tire_pressure: '',
wiper: '',
id:'',
headlight: '',
alertMsg: false
}
editcar = (e, car.id) => {
alert(this.car.id)
e.preventDefault();
const NewCar= {
body_type: this.state.body_type.trim(),
wiper: this.state.wiper,
headlight: this.state.headlight,
make: this.state.make,
link: this.state.link,
engine: this.state.engine,
transmission:this.state.transmission,
vin:this.state.vin,
seat: this.state.seat,
price: this.state.price,
ext_color: this.state.ext_color,
checked: false,
starred: false,
timestamp: timeRef
};
CarsRef.child().update(NewCar);
this.setState({ body_type: '' });
this.setState({ wiper: '' });
this.setState({ make: '' });
this.setState({link:''});
this.setState({ headlight: '' });
this.setState({price: ''});
this.setState({transmission: ''});
this.setState({engine: ''});
this.setState({vin: ''});
this.setState({ext_color: ''});
this.setState({id: ''})
}
I think this might be related to your editcar method. The second parameter is not valid and you probably meant for it to be car and not car.id, so:
change
editcar = (e, car.id) => {}
to
editcar = (e, car) => {}

React - state won't update

i am building small react app and i have strange situation that state won't update. Here is example:
class App extends Component {
constructor() {
super();
this.state = {
locale: 'de',
countryList: [],
fetchInProgress: true,
serverError: {},
person: {
salutation: '',
firstName: '',
lastName: '',
birthDate: '',
nationality: '',
address: '',
zipCode: '',
city: '',
country: '',
mobileNumber: '',
email: '',
correspondanceLanguage: '',
}
};
}
componentDidMount() {
this.setState({
fetchInProgress: false
}),()=>console.log('State updated', this.state)
}
}
I tried also using other approaches:
componentDidMount() {
const temp = {...this.state};
temp.fetchInProgress = false;
this.setState(temp),()=>console.log('State updated', this.state)
}
componentDidMount() {
const temp = {...this.state};
temp['fetchInProgress'] = false;
this.setState(temp),()=>console.log('State updated', this.state)
}
But never gets state updated. Any help?
You have syntax errors in all of your approaches. Note that setState() has the following format:
setState(updater, callback)
where updater can either be a function or an object and where callback is a function.
Starting with your initial approach:
this.setState({
fetchInProgress: false
}),()=>console.log('State updated', this.state)
should instead be:
this.setState({
fetchInProgress: false
},()=>console.log('State updated', this.state))
The other code is correct until, again, you get to the setState() part:
this.setState(temp),()=>console.log('State updated', this.state)
should instead be:
this.setState(temp,()=>console.log('State updated', this.state))

Page load errors due to missing this.setState

I'm getting an error when I populate my form with stored data. My form contains an array so I'm using {this.state.careerHistoryPositions.map((careerHistoryPosition) to create a loop. The error comes from {careerHistoryPosition.errors['company']. This part of the form, is related to errors when the form is submited and I don't store this in the database so when the form is populated, errors isn't set. I assume it's to do with this.setState looking for something that doesn't exist.
Snippet: Constructor
constructor(props) {
super(props);
let uniqueId = moment().valueOf();
const profileCandidateCollection = props.profileCandidate;
const profileCandidateCollectionId = profileCandidateCollection._id;
const careerHistoryPositions = profileCandidateCollection && profileCandidateCollection.careerHistoryPositions;
this.state = {
careerHistoryPositions: careerHistoryPositions || [
{
company: '',
uniqueId: uniqueId,
title: '',
description: '',
startDateMonth: '',
startDateYear: '',
startDateMonth: '',
endDateYear: '',
isCurrent: false,
isDisabled: false,
errors: {}
}
],
profileCandidateCollectionId: profileCandidateCollectionId || null
};
}
Snippet: render
{this.state.careerHistoryPositions.map((careerHistoryPosition) => (
<div key={careerHistoryPosition.uniqueId} className="individual-position">
<SingleInput xs={9} inputType={'text'} controlFunc={this.handleCompanyNameChange(careerHistoryPosition.uniqueId)} content={careerHistoryPosition.company} placeholder={'Company'} bsSize={null}/>
{careerHistoryPosition.errors['company']
? <Col sm={12} className="has-error">
<span className="help-block custom-error">{careerHistoryPosition.errors['company']}</span>
</Col>
: ''}
</div>
))}

Resources