front-end just remove only last item in array - javascript

I'm having a issue with React.
my parent component:
class RoomPrice extends React.Component {
constructor(props){
super(props)
this.state = {
room: this.props.room,
prices: []
};
this.handleDeletePrice = this.handleDeletePrice.bind(this);
}
handleDeletePrice(price_index){
let prices = this.state.prices;
prices.splice(price_index, 1);
this.setState({prices: prices});
}
listPrices(){
console.log(this.state.prices)
return this.state.prices.map((item, index) => {
return (
<AdditionalPrice
key={index}
price={item}
index={index}
handleDeletePrice={this.handleDeletePrice}
/>
)
});
}
renderBasePrice(){
return(
<div id="list_prices">
{ this.listPrices() }
</div>
)
}
render(){
return(
<div>
{this.renderBasePrice()}
</div>
)
}
}
my child component
class AdditionalPrice extends React.Component {
constructor(props){
super(props)
this.state = {
price: this.props.price
}
this.handleKeyChange = this.handleKeyChange.bind(this);
this.handleValueChange = this.handleValueChange.bind(this);
this.handleDeletePrice = this.handleDeletePrice.bind(this);
}
componentWillReceiveProps(nextProps){
this.setState({price: nextProps.price})
}
handleKeyChange(event){
let price = this.state.price;
price.key = event.target.value
this.setState({price: price})
}
handleValueChange(event){
let price = this.state.price;
price.value = event.target.value
this.setState({price: price})
}
handleDeletePrice(){
this.props.handleDeletePrice(this.props.index);
}
renderForm(){
let key = this.state.price.key;
let value = this.state.price.value;
return(
<div className="form-row">
<div className="col-5">
<input type="text" className="form-control" placeholder="Key" onChange={this.handleKeyChange} required/>
</div>
<div className="col-5">
<input type="number" className="form-control" placeholder="Value" onChange={this.handleValueChange} required/>
</div>
<div className="col-2">
<button className="btn btn-warning" type="button" onClick={this.handleDeletePrice}>
<i className="material-icons">delete_forever</i>
</button>
</div>
<input type="hidden" className="form-control" name={"base_price["+key+"]"} value={value} />
</div>
)
}
render() {
return(
<div>
{this.renderForm()}
</div>
)
}
}
i try to delete a item which was get in children, but it always removes last element instead. I thought it have some problem with index
I want to delete the particular element, it always deletes the last element from the render list array.
please help me to sort this problem

Try doing this instead.
handleAddNewPrice(){
const { prices } = this.state;
let new_price = {"key": "", "value": ""}
this.setState({ prices: [...prices, new_price] })
}
Edit
and also this:
handleDeletePrice(price_index){
let prices = [...this.state.prices]; //make a seperate copy of state.
prices.splice(price_index, 1);
this.setState({prices: prices});
}

Problem is in your props. The props.index is received once, so if you want to the delete function worked you need use props.index as a state like price. This is sample codes you need to change in the AdditionalPrice Component:
this.state = {
price: this.props.price,
index: this.props.index
}
componentWillReceiveProps(nextProps){
this.setState({
price: nextProps.price,
index: nextProps.index
})
}
handleDeletePrice(){
this.props.handleDeletePrice(this.state.index);
}

i found the problem
my field in child component haven't set the value. see below
<input type="text" className="form-control" placeholder="Key" value={key} onChange={this.handleKeyChange} required/>
thanks all

Related

Remove multiple div's in reactjs via Remove button

I am trying to remove the multiple div's that have been generated via the add button.
I'm having trouble in understanding how can I send the parent div's id into delete method passed from the child div. Also, if I can store the div's id into a state to perform the deletion process. My code is as follows. I appreciate your inputs and suggestions.
constructor(props) {
super(props);
this.state = {
names: [],
inputValue: '',
id: [],
count: 1,
hostname: '',
devname: '',
sID: '',
}
this.addRow = this.addRow.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
this.deleteRow = this.deleteRow.bind(this)
}
addRow() {
this.setState({ count: this.state.count + 1 })
console.log(`Increase count: ${this.state.count}`)
};
renderDivs() {
let count = this.state.count, uiItems = [];
var { names } = this.state;
let options2 = names.map(name2 => {
return { value: name2.name, label: name2.name };
})
while (count--)
uiItems.push(
<div className="newHost" id="dynamic">
<div className="hostInput">
<input type="text" placeholder="Enter Name"
onChange={this.handleChangeHN.bind(this)}
/>
</div>
<div className="hostInput">
<Select
placeholder="Pick Dev Name..."
styles={colourStyles}
options={options2}
onChange={this.handleChangeDN}
/>
</div>
<div className="hostInput">
<button className="btn btn-danger" type="button" onClick={this.deleteRow}>Remove</button>
</div>
</div>
)
return uiItems;
}
deleteRow(currentID) {
// const changedID = this.state.id.filter(i => i.id !== currentID)
// this.setState({changedID});
// console.log(`Clicked: ${currentID}`);
// this.setState({ count: this.state.count - 1 })
console.log("delete");
};
render() {
let options = sData.map(name => {
return { value: name.name, label: name.name };
})
return (
<div className="wrapper">
<div className="form-wrapper">
<Toolbar />
<form className="form" onSubmit={this.handleSubmit}>
<label className="label1">Select SaleID</label> <hr />
<div>
<Select
value={this.state.inputValue}
onChange={this.handleChange}
options={options}
/>
<div style={{ color: 'red', marginTop: '5px' }}>
{this.state.validationError}
</div>
<br />
</div>
<label className="label1">Create New Sale</label>
<hr />
<div className="addButton">
<button type="button" onClick={this.addRow}>Add</button>
{this.renderDivs()}
</div>
<hr />
<div className="submitButton">
<button type="submit">Submit</button>
</div>
</form>
</div>
</div>
)
}
Thank you in advance!
When programming in react you should first forget about html ids. When you add or delete a row you are dealing with data and not html elements. Your example seems not to contain all of the components code and is missing the functions handleChangeHN and handleChangeHN so I will only make an example of the relevant parts of the code:
constructor(props) {
super(props);
this.state = {
rows: [],
}
//...
}
addRow() {
const newRow = {
name: '',
devName: '',
};
this.setState({ rows: [...this.state.rows, newRow] })
};
deleteRow(position) {
this.setState({ rows: this.state.rows.filter((_, i) => i !== position) })
}
renderDivs() {
const { rows } = this.state;
const options2 = rows.map(name2 => {
return { value: name2.name, label: name2.name };
});
return rows.map( (row, i) => (
<div className="newHost" key="_{i}">
<div className="hostInput">
<input type="text" placeholder="Enter Name"
value={row.name}
onChange={this.handleChangeHN.bind(this)}
/>
</div>
<div className="hostInput">
<Select
placeholder="Pick Dev Name..."
styles={colourStyles}
options={options2}
value={row.devName}
onChange={this.handleChangeDN}
/>
</div>
<div className="hostInput">
<button className="btn btn-danger" type="button" onClick={() => this.deleteRow(i)}>Remove</button>
</div>
</div>
));
}
PS: it is not a good practice to use the iterator as the key key="_{i}" but since you only have user input fields they can not be used as an identifier. The other option would be to use a random id generator or just store the click count in the state and use it as the id when adding new rows.
PPS: as a side note, you should not bind your components handle functions while rendering like you do onChange={this.handleChangeHN.bind(this)}. This will create a new function each time your component is rerendered so it is a slow memory leak. Bind the functions like you did in the constructor or just use the ecmascript 6 syntax handleChangeHN = () => {....

Problem updating parent state from child component in React

I have a class component(actually the collection of the same components) where I have 2 buttons + and - to increase and decrease quantity of watches. Min amount of watches is 1 and max amount is 10. I have regulated this with this 2 functions increaseAmountHandler and decreaseAmountHandler. With this two buttons it's all ok. But the problem is that I have to sum up the value of calculated watches in parent component and I cannot forward the summed up values of the watches to a parent component to state variable totalAmount. Cannot use Redux becacuse it's a collection of watches component and each have own + and - button already occupied with this 2 increaseAmountHandler, decreaseAmountHandler functions.
Anyone idea how to solve this?
Child component:
import React, { Component } from 'react';
import Modal from '.././UI/Modal';
class SelectedWatch extends Component {
constructor(props) {
super(props)
this.state = {
watchQuantity: 1,
watchAmount: 1
}
}
increaseAmountHandler = () => {
if(this.state.watchQuantity < 1) {
this.setState({
watchQuantity: 0,
watchAmount: 0
})
return;
} else if (this.state.watchQuantity >= 10){
this.setState({
watchQuantity: 10,
watchAmount: this.props.selectedWatch.selectedWatchPrice * this.state.watchQuantity
})
return;
}
this.setState({
watchQuantity: this.state.watchQuantity + 1,
watchAmount: this.props.selectedWatch.selectedWatchPrice * this.state.watchQuantity
})
}
decreaseAmountHandler = () => {
if(this.state.watchQuantity < 1) {
this.setState({
watchQuantity: 0,
watchAmount: 0
})
return;
} else if (this.state.watchQuantity >= 10){
this.setState({
watchQuantity: 9,
watchAmount: this.props.selectedWatch.selectedWatchPrice * this.state.watchQuantity
})
return;
}
this.setState({
watchQuantity: this.state.watchQuantity - 1,
watchAmount: this.props.selectedWatch.selectedWatchPrice * this.state.watchQuantity
})
}
render() {
return (
<div className={"shopping-cart-product" + (this.state.watchQuantity < 1 ? ' notDisplayed' : '')}>
<div className="product-info">
<div>
<h3>{this.props.selectedWatch.selectedWatchName}</h3>
<p>${this.props.selectedWatch.selectedWatchPrice} × {this.state.watchQuantity}</p>
</div>
<img src={this.props.selectedWatch.selectedWatchUrl} />
</div>
<div className="product-count">
<button onClick={this.decreaseAmountHandler}>-</button>
<span>{this.state.watchQuantity}</span>
<button onClick={this.increaseAmountHandler}>+</button>
</div>
</div>
);
}
}
export default SelectedWatch;
Parent component:
import React, { Component } from 'react';
import EnteredWatch from '.././components/EnteredWatch/EnteredWatch';
import SelectedWatch from '.././components/SelectedWatch/SelectedWatch';
class App extends Component {
constructor(props) {
super(props)
this.state = {
watchName: '',
watchDescription: '',
watchUrl: '',
watchPrice: '',
watchId: '',
watchAmount: '',
watchQuantity: 1,
enteredWatchList: [],
selectedWatchName: '',
selectedWatchDescription: '',
selectedWatchUrl: '',
selectedWatchPrice: '',
selectedWatchId: '',
selectedWatchAmount: '',
selectedWatchQuantity: 1,
selectedWatchList: [],
totalAmount: 0,
}
}
submitHandler = (event) => {
event.preventDefault();
let watchId = Math.floor((Math.random() * 100) + 1);
let watchName = this.state.watchName;
let watchDescription = this.state.watchDescription;
let watchUrl = this.state.watchUrl;
let watchPrice = this.state.watchPrice;
let watchQuantity = this.state.watchQuantity;
this.setState({
enteredWatchList: this.state.enteredWatchList.concat({watchName, watchUrl, watchDescription, watchPrice, watchId, watchQuantity})
})
add = (selectedWatchName, selectedWatchUrl, selectedWatchDescription, selectedWatchPrice, index, selectedWatchQuantity) => {
let arr = this.state.selectedWatchList;
let found = arr.some(el => {
return el.selectedWatchName === selectedWatchName;
});
if (!found) {
return arr.concat({selectedWatchName, selectedWatchUrl, selectedWatchDescription, selectedWatchPrice, index, selectedWatchQuantity});
} else {
return this.state.selectedWatchList;
}
}
buyWatchHandler = (selectedWatchName, selectedWatchUrl, selectedWatchDescription, selectedWatchPrice, index, selectedWatchQuantity) => {
let arr = this.add(selectedWatchName, selectedWatchUrl, selectedWatchDescription, selectedWatchPrice, index, selectedWatchQuantity);
this.setState({
selectedWatchName: selectedWatchName,
selectedWatchUrl: selectedWatchUrl,
selectedWatchDescription: selectedWatchDescription,
selectedWatchPrice: selectedWatchPrice,
selectedWatchId: index,
selectedWatchQuantity: selectedWatchQuantity,
selectedWatchList: arr
});
}
render() {
const enteredWatches = this.state.enteredWatchList.map((enteredWatch, index) => {
return <EnteredWatch
key={index}
enteredWatch={enteredWatch}
selected={this.buyWatchHandler.bind(this, enteredWatch.watchName, enteredWatch.watchUrl,
enteredWatch.watchDescription, enteredWatch.watchPrice, index, enteredWatch.watchQuantity)}
/>
});
const selectedWatches = this.state.selectedWatchList.map((selectedWatch, index) => {
const active = this.state.activeIndex;
return <SelectedWatch
key={index}
active={index === active}
selectedWatch={selectedWatch}
/>
});
return (
<div className="App">
<div className="container-fluid">
<div className="container">
<div className="add-product">
<form>
<div>
<label>Product name:</label>
<input
type="text"
placeholder="Casio Watch"
required
value={this.state.watchName}
onChange={event => this.setState({watchName: event.target.value})}
/>
</div>
<div>
<label>Product description:</label>
<textarea
placeholder="Sample description..."
value={this.state.watchDescription}
onChange={event => this.setState({watchDescription: event.target.value})}
>
</textarea>
</div>
<div>
<label>Product image:</label>
<input
type="text"
placeholder="http://...jpg"
value={this.state.watchUrl}
pattern="https?://.+" required
onChange={event => this.setState({watchUrl: event.target.value})}
/>
</div>
<div>
<label>Product price:</label>
<input
type="number"
min="0"
placeholder="22"
value={this.state.watchPrice}
onChange={event => this.setState({watchPrice: event.target.value})}
/>
</div>
<button
type="submit"
onClick={event => this.submitHandler(event)}
>
Add a new Task
</button>
</form>
</div>
<div className="list-products">
<ul>
{enteredWatches}
</ul>
</div>
<div className="shopping-cart">
<div className="shopping-cart-products">
<ul>
{selectedWatches}
</ul>
</div>
<div className="shopping-cart-summary">
<div>Total: <b>${this.state.totalAmount}</b></div>
<div><button onClick={this.summaryHandler}>Purchase</button></div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default App;
The parent has to keep track of how many watches have been added.
Make the parent smart (has state), and the children dumb (no state).
Manage all the state in the parent, and put the click handlers in the parent too.
Pass those handlers down to the child, to be fired when its buttons are clicked. Something like this:
class Parent extends React.Component {
this.state = {
cart: [],
watches: [
{ id: 1, name: "Casio", description: "...", price: 25 },
{ id: 2, name: "Rolex", description: "...", price: 3000 },
{ id: 3, name: "Timex", description: "...", price: 10 },
],
}
handleClickIncrement = (watchId) => {
//add it to the cart (or increment it if its already there)
}
handleClickDecrement = (watchId) => {
//remove it from the cart (or deccrement it if its already there)
}
getCartTotal() {
//loop over cart and calculate
}
renderWatches() {
this.state.watches.map(watch => (
<Watch id={watch.id}
name={watch.name}
description={watch.description}
price={watch.price}
onClickIncrement={() => { this.handleClickIncrement(watch.id); }}
onClickDecrement={() => { this.handleClickDecrement(watch.id); }}
))
}
render() {
<div>
<h1>Our selection of watches:</h1>
{this.renderWatches()}
<h1>Your cart total: {this.getCartTotal()}</h1>
</div>
}
}
class Watch extends React.Component {
props = {
id,
name,
description,
price,
quantityInCart,
onClickIncrementButton,
onClickDecrementButton
}
render() {
<div>
<h1>{this.props.name}</h1>
<p>{this.props.description}</p>
<h5>${this.props.price}</h5>
<button onClick={this.props.onClickIncrementButton}>+</button>
<button onClick={this.props.onClickDecrementButton}>-</button>
</div>
}
}

In React, how to bind an input's value when rendering a list of inputs?

I'm rendering a list of inputs and I want to bind each input's value to a link's href. My current attempt renders https://twitter.com/intent/tweet?text=undefined:
class App extends React.Component {
tweets = [
{ id: 1, link: 'example.com' },
{ id: 2, link: 'example2.com' }
];
render() {
return (
<div>
{this.tweets.map(tweet =>
<div key={tweet.id}>
<input type="text" placeholder="text" onChange={e => tweet.text = e.target.value} />
<a href={`https://twitter.com/intent/tweet?text=${tweet.text}`}>Tweet</a>
</div>
)}
</div>
);
}
}
This probably needs to involve setState but I have no idea how to achieve that when rendering a list. I've tried to do some research on this but didn't found anything helpful.
JSFiddle: https://jsfiddle.net/nunoarruda/u5c21wj9/3/
Any ideas?
You can move the tweets variable to the state to maintain consistency in that array.
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
tweets: [
{ id: 1, link: 'example.com' },
{ id: 2, link: 'example2.com' }
]
};
};
setTweets = index => e => {
const { tweets } = this.state
tweets[index].text = e.target.value
this.setState({ tweets })
}
render() {
const { tweets } = this.state
return (
<div>
{tweets.map((tweet, index) =>
<div key={tweet.id}>
<input type="text" placeholder="text" onChange={this.setTweets(index)} />
<a href={`https://twitter.com/intent/tweet?text=${tweet.text}`}>Tweet</a>
</div>
)}
</div>
);
}
}
Updated Jsfiddle: https://jsfiddle.net/u5c21wj9/6/
You can reach the desired result using state.
return (
<div>
{tweets.map(({ id, link }) =>
<div key={id}>
<input type="text" placeholder="text" onChange={({ target }) => this.setState({ [id]: target.value })} />
<a href={`https://twitter.com/intent/tweet?text=${this.state[id] || link}`}>Tweet</a>
</div>
)}
</div>
);
Note: I would move tweets outside the component and implement few ES6 features.
Updated Jsfiddle: https://jsfiddle.net/u5c21wj9/7/
You really should use a state here and make your tweets variable be part of it. To do that, add a constructor:
constructor() {
super();
this.state = {
tweets: [
{ id: 1, link: 'example.com' },
{ id: 2, link: 'example2.com' }
]
};
}
Then you need to mutate each linkwhenever you type in one of the inputs. There are a few pitfalls here, so let me go through them one-by-one:
changeTweet = (id, e) => {
let arr = this.state.tweets.slice();
let index = arr.findIndex(i => i.id === id);
let obj = Object.assign({}, arr[index]);
obj.link = e.target.value;
arr[index] = obj;
this.setState({tweets: arr});
}
First, you need to create a copy of your state variable. This gives you something to work with, without mutating the state directly which is anti-pattern. This can be done with slice().
Since you are sending in the id of the object to modify, we need to find it in our array (in case the items are unordered). This is done with findIndex(). You might want to handle the scenario in which such index is not found (I have not done that).
Now we know where in the array the object with the given id key is. Now, create a copy of that item (which is an object). This is also to prevent mutating the state directly. Do this with Object.assign().
Now change the link to the input value we typed in. Replace the old item object with the new one (obj) and replace the old tweets array with the new one (arr).
Here's the full example:
class App extends React.Component {
constructor() {
super();
this.state = {
tweets: [
{ id: 1, link: 'example.com' },
{ id: 2, link: 'example2.com' }
]
};
}
changeTweet = (id, e) => {
let arr = this.state.tweets.slice();
let index = arr.findIndex(i => i.id === id);
let obj = Object.assign({}, arr[index]);
obj.link = e.target.value;
arr[index] = obj;
this.setState({tweets: arr});
}
render() {
return (
<div>
{this.state.tweets.map(tweet =>
<div key={tweet.id}>
<input type="text" placeholder="text" onChange={(e) => this.changeTweet(tweet.id, e)} />
<a href={`https://twitter.com/intent/tweet?text=${tweet.link}`}>Tweet</a>
</div>
)}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
You need to save the text from the input in the state (using setState), not in the tweets array. Then you can render it getting the text from the state.
class App extends React.Component {
tweets = [
{ id: 1, link: 'example.com' },
{ id: 2, link: 'example2.com' }
];
state = {
tweetsText :{}
}
handleTextChange = (event, tweetId) => {
const tweetsTextCopy = Object.assign({}, this.state.tweetsText)
tweetsTextCopy[tweetId] = event.target.value
this.setState({tweetsText: tweetsTextCopy})
}
render() {
return (
<div>
{this.tweets.map(tweet =>
<div key={tweet.id}>
<input type="text" placeholder="text" onChange={e => this.handleTextChange(e, tweet.id)} />
<a href={`https://twitter.com/intent/tweet?text=${this.state.tweetsText[tweet.id]}`}>Tweet</a>
</div>
)}
</div>
);
}
}
Links info is in the link property of your tweets array. The property text is not defined.
So, your render function should look like this
render() {
return (
<div>
{this.tweets.map(tweet =>
<div key={tweet.id}>
<input type="text" placeholder="text" onChange={e => tweet.text= e.target.value} />
<a href={`https://twitter.com/intent/tweet?text=${tweet.link}`}>Tweet</a>
</div>
)}
</div>
);
}

React: Adding an input component via a button and updating its state

I am trying to create a button that will add a new input element to a page and then as I type display its changes.
However when I type into the input fields in <Input />, for some reason the state isn't changing. The input fields stay blank.
Out of curiosity, I removed the button that adds the <Input /> component and ran it with one <Input /> field on the page. When I type into one of the input fields, I can see my text.
It seems that when I add a new component to the page and try to change the state, something is off.
What am I doing wrong?
function Input(props) {
console.log(props)
return (
<div>
<div><input name="pitchName" value={props.currentValue.pitchName} placeholder="Pitch Name" onChange = {props.updateNewPitch}/></div>
<div><input name="shortCut" value={props.currentValue.shortcut} placeholder="Short cut" onChange = {props.updateNewPitch} /></div>
<div><input name="subject" value={props.currentValue.subject} placeholder="Subject" onChange = {props.updateNewPitch} /></div>
<div><textarea name="pitch" value={props.currentValue.pitch} onChange = {props.updateNewPitch}/></div>
<button type="submit" onClick={props.savePitch} >Add Pitch</button>
</div>
)
}
// function SavedPitches(props)
class Form extends React.Component{
constructor(props){
super(props);
this.state = {
inputList: [],
addNewPitch: {
pitchName: '',
shortCut: '',
subject: '',
pitch: ''
},
savedPitches: []
};
this.onAddBtnClick = this.onAddBtnClick.bind(this)
this.savePitch = this.savePitch.bind(this)
this.updateNewPitch = this.updateNewPitch.bind(this)
}
updateNewPitch(e){
this.setState({addNewPitch: {...this.state.addNewPitch, [e.target.name]: e.target.value}})
}
onAddBtnClick(event){
const inputList = this.state.inputList;
this.setState({
inputList: inputList.concat(
<Input savePitch={this.savePitch}
currentValue = {this.state.addNewPitch}
updateNewPitch={this.updateNewPitch}
/>
)
})
}
render() {
return(
<div>
<button onClick={this.onAddBtnClick}>Add input</button>
<div></div>
{
this.state.inputList
}
</div>
)
}
}
ReactDOM.render(<Form />,document.getElementById('root'));
Reason is because you are storing the Input (UI element) in state variable, and that variable is not getting update only values are getting updated in a separate state variable addNewPitch.
Suggestion:
1- Storing UI elements in state variable is not a good idea, always store value in state and all the ui logic should be inside render function.
2- Use a state variable and toggle the Input (UI element) on the basis of that.
Check working solution (check the values on addNewPitch inside render it will get updated properly):
function Input(props) {
return (
<div>
<div><input name="pitchName" value={props.currentValue.pitchName} placeholder="Pitch Name" onChange = {props.updateNewPitch}/></div>
<div><input name="shortCut" value={props.currentValue.shortcut} placeholder="Short cut" onChange = {props.updateNewPitch} /></div>
<div><input name="subject" value={props.currentValue.subject} placeholder="Subject" onChange = {props.updateNewPitch} /></div>
<div><textarea name="pitch" value={props.currentValue.pitch} onChange = {props.updateNewPitch}/></div>
<button type="submit" onClick={props.savePitch} >Add Pitch</button>
</div>
)
}
class Form extends React.Component{
constructor(props){
super(props);
this.state = {
inputList: [],
addNewPitch: {
pitchName: '',
shortCut: '',
subject: '',
pitch: ''
},
savedPitches: []
};
this.onAddBtnClick = this.onAddBtnClick.bind(this)
this.savePitch = this.savePitch.bind(this)
this.updateNewPitch = this.updateNewPitch.bind(this)
}
savePitch() {
}
updateNewPitch(e){
this.setState({addNewPitch: {...this.state.addNewPitch, [e.target.name]: e.target.value}})
}
onAddBtnClick(event){
const inputList = this.state.inputList;
this.setState({
show: true,
addNewPitch: {
pitchName: '',
shortCut: '',
subject: '',
pitch: ''
}
})
}
render() {
console.log('addNewPitch', this.state.addNewPitch);
return(
<div>
<button onClick={this.onAddBtnClick}>Add input</button>
<div></div>
{
this.state.show && <Input
savePitch={this.savePitch}
currentValue = {this.state.addNewPitch}
updateNewPitch={this.updateNewPitch}
/>
}
</div>
)
}
}
ReactDOM.render(<Form />,document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='root'/>

How do you display an array of objects in react

I have this code which takes three input fields and i store them in an object when i click submit and displays them. But it only displays the current value and not all the value which I've entered into the array of objects.
class Emp1 extends React.Component {
constructor(props) {
super(props);
this.state = {
obj: {name :'', email: '', age: '', phone: ''},
items: []
}
}
save(e) {
e.preventDefault();
var obj1 = this.state.obj;
obj1.name = ReactDOM.findDOMNode(this.refs.field.refs.name1).value;
obj1.email = ReactDOM.findDOMNode(this.refs.field.refs.email1).value;
obj1.age = ReactDOM.findDOMNode(this.refs.field.refs.age1).value;
obj1.phone = ReactDOM.findDOMNode(this.refs.field.refs.phone1).value;
var arr = [];
arr.push(obj1)
this.setState({
obj: obj1,
items: arr
})
}
render() {
return(
<div>
<Fields ref="field" save={this.save.bind(this)}/>
<Display items={this.state.obj} />
</div>
)
}
}
class Fields extends React.Component {
render() {
return(
<div>
<label>Name</label>
<input type="text" ref="name1" /><br/>
<label>Email</label>
<input type="email" ref="email1" /><br/>
<label>Age</label>
<input type="text" ref="age1" /><br/>
<label>Phone Number</label>
<input type="text" ref="phone1" /><br/>
<button type="submit" onClick={ this.props.save }>Submit</button>
</div>
)
}
}
class Display extends React.Component {
render(){
return (
<div>
<ul>
<li><b>Name:</b> {this.props.items.name}</li>
<li><b>Email:</b> {this.props.items.email}</li>
<li><b>Age:</b> {this.props.items.age}</li>
<li><b>Phone:</b> {this.props.items.phone}</li>
</ul>
</div>
)
}
}
export default Emp1;
If what you want is to display all the form's values that have been sent, you can try what I did.
I changed your state structure, your "save" method and the render method of the class "Emp1" to display every single submitted forms.
class Emp1 extends React.Component {
constructor(props) {
super(props);
this.state = {
items: []
}
}
save(e) {
e.preventDefault();
var obj1 = {};
obj1.name = ReactDOM.findDOMNode(this.refs.field.refs.name1).value;
obj1.email = ReactDOM.findDOMNode(this.refs.field.refs.email1).value;
obj1.age = ReactDOM.findDOMNode(this.refs.field.refs.age1).value;
obj1.phone = ReactDOM.findDOMNode(this.refs.field.refs.phone1).value;
var newArr = this.state.items.slice();
newArr.push(obj1)
this.setState({
items: newArr
})
}
render() {
let displayItems = this.state.items.map((thisForm) => (
<Display items={thisForm}/>
))
return(
<div>
<Fields ref="field" save={this.save.bind(this)}/>
{displayItems}
</div>
)
}
}
class Fields extends React.Component {
render() {
return(
<div>
<label>Name</label>
<input type="text" ref="name1" /><br/>
<label>Email</label>
<input type="email" ref="email1" /><br/>
<label>Age</label>
<input type="text" ref="age1" /><br/>
<label>Phone Number</label>
<input type="text" ref="phone1" /><br/>
<button type="submit" onClick={ this.props.save }>Submit</button>
</div>
)
}
}
class Display extends React.Component {
render(){
return (
<div>
<ul>
<li><b>Name:</b> {this.props.items.name}</li>
<li><b>Email:</b> {this.props.items.email}</li>
<li><b>Age:</b> {this.props.items.age}</li>
<li><b>Phone:</b> {this.props.items.phone}</li>
</ul>
</div>
)
}
}
When you write this
var arr = [];
arr.push(obj1)
this.setState({
obj: obj1,
items: arr
})
You create a new empty array, then reset the state.items with this new array that contains only 1 obj
Try like this
//var arr = [];
//arr.push(obj1)
this.setState({
obj: obj1,
items: [...this.state.items, obj1] // this will create new array from old with new item
})
to print all values in the array.. you need to iterate over the items array..
this is what is missing in the code..
put the below modification in the render block of 1st component(Emp1)
render() {
let displayElems = this.state.items.map((d) => {
return <Display items={d} />;
});
return(
<div>
<Fields ref="field" save={this.save.bind(this)}/>
{displayElems}
</div>
)
}
hope this will work..
I just modified your code for simplicity.
you should make some naming change.. e.g. <Display items={d} />
here intstead of items - item should be used :-)

Categories