Reputation: 340
my question is a little complicated, I am building a trip-related web application where users can book trips. So I have made a function that increases the number of travelers as the user clicks the + sign. when this function is called it changes the state and another function gets triggered that displays the form to fill in the traveler details. Now this form is rendered according to the number of travelers traveling. how can I set that data in an array of objects?
here's a screenshot guide:
I want the data to be in the state like this:
travelersDetail: [{firstName: 'Farrukh', lastName:'Ayaz', address:'...', city:'Lahore'},
{firstName: 'Dwight', lastName:'Schrute', address:'...', city:'Scranton'},
{firstName: 'Micheal', lastName:'Scott', address:'...', city:'Scranton'},]
My code:
// state
state = {
NumOfTravellers : 1,
travelersDetail: [],
trip: null,
}
// the functions that increases the number of travelers
handleClick = (e) =>{
e.preventDefault();
if(e.target.id == 'plus'){
this.setState({NumOfTravellers: this.state.NumOfTravellers + 1 })
}
else if(e.target.id == 'minus'){
this.state.NumOfTravellers > 1 ? this.setState({NumOfTravellers:
this.state.NumOfTravellers - 1 }) : alert("can't be less than that :)")
}
}
// the function that returns the traveler details form, according to the number of travelers traveling.
const numberOfTravelers = () =>{
var travellers = [];
for(let t = 0; t < this.state.NumOfTravellers; t++){
travellers.push(
<div >
<h4> Traveller # {t+1} Details</h4><br/>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="firstName">First Name</label>
<input type="firstName" className="form-control" onChange={this.handleTDChange} id="firstName" placeholder="FirstName" />
</div>
<div className="form-group col-md-6">
<label htmlFor="lastName">Last Name</label>
<input type="lastName" className="form-control" onChange={this.handleTDChange} id="lastName" placeholder="LastName" />
</div>
</div>
<div className="form-group">
<label htmlFor="address">Address</label>
<input type="text" className="form-control" onChange={this.handleTDChange} id="address" placeholder="1234 Main St" />
</div>
<div className="form-group">
<label htmlFor="phoneNumber">Phone Number</label>
<input type="tel" className="form-control" onChange={this.handleTDChange} id="phoneNumber" placeholder="+92..." />
</div>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="city">City</label>
<select onChange={this.handleTDChange} id="city" className="form-control">
<option selected>Choose...</option>
<option>Lahore</option>
<option>Islamabad</option>
<option>Karachi</option>
<option>Rawalpindi</option>
<option>Quetta</option>
<option>Multan</option>
</select>
</div>
<div className="form-group col-md-4">
<label htmlFor="state">State</label>
<select onChange={this.handleTDChange} id="state" className="form-control">
<option selected>Choose...</option>
<option>Pakistan</option>
</select>
</div>
<div className="form-group col-md-2">
<label htmlFor="zip">Zip</label>
<input type="text" className="form-control" onChange={this.handleTDChange} id="zip" />
</div>
</div>
</div>);
}
return travellers
}
Upvotes: 1
Views: 2915
Reputation: 1054
I don't completely understand you problem, what I understand is.
There is a controller, Plus and Minus. On click of Plus a new Traveler form has to be added and on click of minus the last Travelers form will be removed. And also the traveler counter is incremented or decremented based on the button click
You would not want 2 variables, 1 to keep track of the number of travelers and other to store the traveler details, you can maintain only 1 variable. Just have traverlerDetails, we can get the number of travelers form the size of the traverlerDeterails array.
// state values
this.state = {
travelersDetail: [],
trip: null,
};
handleClick = (clickEvent) => {
clickEvent.preventDefault();
const travelersDetailCopy = [...this.state.travelersDetail];
if (e.target.id == 'plus') {
travelersDetailCopy.push({
firstName: '', lastName: '', address: '', city: '' // Add empty data
});
} else if (e.target.id == 'minus') {
if (this.state.travelersDetail.length === 1) {
alert("Can't be less than 1");
} else {
travelersDetailCopy.pop();
}
}
this.setState({
travelersDetail: travelersDetailCopy
});
}
const numberOfTraverlers = () => {
return this.state.travelersDetail.map((travelerDetails, index) => {
return (
<div key={index}>
<h4> Traveller # {index + 1} Details</h4><br />
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="firstName">First Name</label>
<input type="firstName" className="form-control" onChange={(event) => {this.handleTDChange(event, index, "firstName")}} id="firstName" placeholder="FirstName" />
</div>
<div className="form-group col-md-6">
<label htmlFor="lastName">Last Name</label>
<input type="lastName" className="form-control" onChange={(event) => {this.handleTDChange(event, index, "lastName")}} id="lastName" placeholder="LastName" />
</div>
</div>
<div className="form-group">
<label htmlFor="address">Address</label>
<input type="text" className="form-control" onChange={(event) => {this.handleTDChange(event, index, "address")}} id="address" placeholder="1234 Main St" />
</div>
<div className="form-group">
<label htmlFor="phoneNumber">Phone Number</label>
<input type="tel" className="form-control" onChange={(event) => {this.handleTDChange(event, index, "phoneNumber")}} id="phoneNumber" placeholder="+92..." />
</div>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="city">City</label>
<select onChange={(event) => {this.handleTDChange(event, index, "city")}} id="city" className="form-control">
<option selected>Choose...</option>
<option>Lahore</option>
<option>Islamabad</option>
<option>Karachi</option>
<option>Rawalpindi</option>
<option>Quetta</option>
<option>Multan</option>
</select>
</div>
<div className="form-group col-md-4">
<label htmlFor="state">State</label>
<select onChange={(event) => {this.handleTDChange(event, index, "state")}} id="state" className="form-control">
<option selected>Choose...</option>
<option>Pakistan</option>
</select>
</div>
<div className="form-group col-md-2">
<label htmlFor="zip">Zip</label>
<input type="text" className="form-control" onChange={(event) => {this.handleTDChange(event, index, "zip")}} id="zip" />
</div>
</div>
</div>
)
})
}
handleTDChange(event, index, updateField) {
const arrayCopy = [...this.state.travelersDetail];
arrayCopy[index][updateField] = event.target.value;
this.setState({travelersDetail: arrayCopy});
}
Use this.state.travelersDetail.length
to display the number of travelers.
Don't use for-loop, make use of built in functions like forEach, map, filter and other methods.
Update : To handle onChange events, you can have multiple handleChange event handler.
But if you want to do it in a single, you can pass few additional argument. First being the actual event, second the index of the travelerDetails object, third being the property that needs to be updated.
There is a much better way of doing this, extract the content in side the map and create a separate component. Which would contain the logic related to the component. With this updation and also maintenance of the code is much easier
Upvotes: 2
Reputation: 873
You should be using the array.push() method detailed in javascript to add an element to an existing array.
Example
const array = [];
array.push({ id: 'someId', name: 'someName' });
See documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push
Upvotes: 0