multiple textfields onChange function issue - javascript

There's a plus button to increase the number of textfields in the page. After increasing the textfields, I want to show all the textfield input value at once under, after clicking on the submit button.
But here it's giving a problem on the onChange setState issue. How to handle it ? Any help ?
Here's the => DEMO
class App extends Component {
constructor(props) {
super(props);
this.state = {
arr: [],
firstname: '',
lastname: '',
setarr: [],
temp: []
};
this.addTextfields = this.addTextfields.bind(this);
this.changeFirstname = this.changeFirstname.bind(this);
this.changeLastname = this.changeLastname.bind(this);
}
addTextfields(e) {
let htmlContent = [];
htmlContent.push(
<div>
<input type="text" placeholder="first name" onChange={this.changeFirstname} value={this.state.firstname} /> <br/> <br/>
<input type="text" placeholder="last name" onChange={this.changeLastname} value={this.state.lastname} /> <br/> <br/>
</div>
);
this.setState({ arr: this.state.arr.concat(htmlContent) });
}
changeFirstname(e) {
this.setState({ firstname: e.target.value });
}
changeLastname(e) {
this.setState({ lastname: e.target.value });
}
showTexts() {
console.log(this.state.firstname, this.state.lastname);
var add = [this.state.firstname, this.state.lastname];
this.state.temp = this.state.temp.concat(add);
this.setState({ setarr: this.state.temp, firstname: '', lastname: '' });
// localStorage.setItem(this.state.arr, 'names');
}
render() {
return (
<div>
<div className="App">
<input type="text" onChange={this.changeFirstname} placeholder="first name" value={this.state.firstname} /> <br/> <br/>
<input type="text" onChange={this.changeLastname} placeholder="last name" value={this.state.lastname} /> <br/> <br/>
<button type="submit" onClick={this.addTextfields}>Plus</button>
{this.state.arr}
</div>
<div className="submit-button">
<button type="submit" onClick={this.showTexts.bind(this)}>Submit</button>
</div>
<div>
{this.state.setarr}
</div>
</div>
);
}
}
render(<App />, document.getElementById('root'));

Do it this way.
import React, { Component } from "react";
import { render } from "react-dom";
class App extends Component {
constructor(props) {
super(props);
this.state = {
arr: [
{
firstname: "",
lastname: ""
}
],
displayValues: []
};
this.addTextfields = this.addTextfields.bind(this);
this.changeFirstname = this.changeFirstname.bind(this);
this.changeLastname = this.changeLastname.bind(this);
}
addTextfields(e) {
let arr = this.state.arr;
arr.push({
firstname: "",
lastname: ""
});
this.setState({ arr });
}
changeFirstname(e, index) {
let arr = this.state.arr;
arr[index].firstname = e.target.value;
this.setState({ arr });
}
changeLastname(e, index) {
let arr = this.state.arr;
arr[index].lastname = e.target.value;
this.setState({ arr });
}
showTexts() {
let displayValues = [];
this.state.arr.map(element => {
console.log(element.firstname, element.lastname);
var add = element.firstname + " " + element.lastname;
displayValues.push(add);
});
this.setState({ displayValues });
}
render() {
return (
<div>
<div className="App">
{this.state.arr.map((element, index) => {
return (
<div key={index}>
<input
type="text"
onChange={e => this.changeFirstname(e, index)}
placeholder="first name"
value={this.state.firstname}
/>{" "}
<br /> <br />
<input
type="text"
onChange={e => this.changeLastname(e, index)}
placeholder="last name"
value={this.state.lastname}
/>{" "}
<br /> <br />
</div>
);
})}
<button type="submit" onClick={this.addTextfields}>
Plus
</button>
</div>
<div className="submit-button">
<button type="submit" onClick={this.showTexts.bind(this)}>
Submit
</button>
</div>
<div>
{this.state.displayValues.map(element => {
return <p>{element}</p>;
})}
</div>
</div>
);
}
}
render(<App />, document.getElementById("root"));

I think, you are doing it the wrong way. I have created the below sample for reference. Please have a look.
const Form = (props) => {
return(
<div>
<input type="text" placeholder="first name" onChange={props.changeFirstname} value={props.firstname} /> <br/> <br/>
<input type="text" placeholder="last name" onChange={props.changeLastname} value={props.lastname} /> <br/> <br/>
</div>
)
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
arr: [
{
firstname: '',
lastname: '',
id:1
}
],
showOutput:false
};
this.addTextfields = this.addTextfields.bind(this);
this.changeFirstName = this.changeFirstName.bind(this);
this.changeLastName = this.changeLastName.bind(this);
}
addTextfields(e) {
debugger
let oldArray = this.state.arr;
this.setState((prevState) => {
return {
arr: oldArray.concat({
firstname: '',
lastname: '',
id: prevState.arr.length + 2
})
}
});
}
changeFirstName(e, selectedIndex) {
let updatedArray = this.state.arr.map((data) => {
if(data.id === selectedIndex) {
return Object.assign({}, data, {
firstname: e.target.value
})
} else {
return data
}
})
this.setState({ arr: updatedArray });
}
changeLastName(e, selectedIndex) {
let updatedArray = this.state.arr.map((data) => {
if(data.id === selectedIndex) {
return Object.assign({}, data, {
lastname: e.target.value
})
} else {
return data
}
})
this.setState({ arr: updatedArray });
}
showTexts() {
this.setState({
showOutput: true
})
}
render() {
return (
<div>
<div className="App">
{
this.state.arr.map((data, index) => {
return <Form key={index} data={data}
changeFirstname={(e) => this.changeFirstName(e, data.id)}
changeLastname={(e) => this.changeLastName(e, data.id)}
/>
})
}
<button type="submit" onClick={this.addTextfields}>Plus</button>
</div>
<div className="submit-button">
<button type="submit" onClick={this.showTexts.bind(this)}>Submit</button>
</div>
<div>
{
this.state.showOutput &&
this.state.arr.map((data, index) => {
return <div>
{data.firstname} {data.lastname}
</div>
})
}
</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>
Hope this helps.

Related

Add multiple input field dynamically in react

I have is a div that contains three input elements and a remove button. what is required is when the user clicks on the add button it will add this div dynamically and when the user clicks on the remove button it will remove this div. I was able to add one input element (without div container) dynamically with the following method.
create an array in the state variable.
assign a name to the dynamic input field with the help of array indexing like name0, name1
How can I do with these many input fields? The problem grows further when I create this whole div as a separate component. I am using a class-based component.
handleChange=(event) =>
{
this.setState({[event.target.name]:event.target.values});
}
render()
{
return(
<div className="row">
<button type="button" onClick={this.addElement}>Add</button>
<div className="col-md-12 form-group">
<input type="text" className="form-control" name="name" value={this.state.name} onChange={this.handleChange} />
<input type="text" className="form-control" name="email" value={this.state.email} onChange={this.handleChange} />
<input type="text" className="form-control" name="phone" value={this.state.phone} onChange={this.state.phone} />
<button type="button" onClick={this.removeElement}>Remove</button>
</div>
</div>
)
}
I would approach this from a configuration angle as it's a little more scalable. If you want to eventually change across to something like Formik or React Form, it makes the move a little easier.
Have an array of objects that you want to turn into input fields. Your main component should maintain state whether the <Form /> component is showing, and if it's visible pass in the config and any relevant handlers.
Your form component should maintain state for the inputs, and when you submit it, passes up the completed state to the parent.
const { Component } = React;
class Example extends Component {
constructor(props) {
super();
// The only state in the main component
// is whether the form is visible or not
this.state = { visible: false };
}
addForm = () => {
this.setState({ visible: true });
}
removeForm = () => {
this.setState({ visible: false });
}
handleSubmit = (form) => {
console.log(form);
}
render() {
const { visible } = this.state;
const { config } = this.props;
return (
<div>
<button
type="button"
onClick={this.addForm}
>Add form
</button>
{visible && (
<Form
config={config}
handleSubmit={this.handleSubmit}
handleClose={this.removeForm}
/>
)}
</div>
);
}
};
class Form extends Component {
constructor(props) {
super();
this.state = props.config.reduce((acc, c) => {
return { ...acc, [c.name]: '' };
}, {});
}
handleChange = (e) => {
const { name, value } = e.target;
this.setState({ [name]: value });
}
handleSubmit = () => {
this.props.handleSubmit(this.state);
}
render() {
const { name, email, phone } = this.state;
const { handleClose, config } = this.props;
return (
<div onChange={this.handleChange}>
{config.map(input => {
const { id, name, type, required } = input;
return (
<div>
<label>{name}</label>
<input key={id} name={name} type={type} required={required} />
</div>
)
})}
<button type="button" onClick={this.handleSubmit}>Submit form</button>
<button type="button" onClick={handleClose}>Remove form</button>
</div>
);
}
}
const config = [
{ id: 1, name: 'name', type: 'text', required: true },
{ id: 2, name: 'email', type: 'email', required: true },
{ id: 3, name: 'phone', type: 'phone', required: true }
];
ReactDOM.render(
<Example config={config} />,
document.getElementById('react')
);
input { display: block; }
label { text-transform: capitalize; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
I hope this would be help for your question.
I made a child component which have three input tags.
// parent component
import React, { Component } from "react";
import TextField from "./TextField";
class App extends Component {
constructor(props) {
super(props);
this.state = {
users: [
{
key: Date.now(),
name: "",
email: "",
phone: ""
}
]
};
}
onChange = (inputUser) => {
this.setState((prevState) => {
const newUsers = prevState.users.map((element) => {
if (element.key === inputUser.key) return inputUser;
return element;
});
return { users: newUsers };
});
};
addElement = () => {
const { name, email, phone } = this.state;
this.setState((prevState) => ({
users: prevState.users.concat({
key: Date.now(),
name,
email,
phone
})
}));
};
removeElement = (id) => {
this.setState((prevState) => ({
users: prevState.users.filter((user) => user.key !== id)
}));
};
render() {
const { users } = this.state;
return (
<div className="row">
<button type="button" onClick={this.addElement}>
Add
</button>
<div className="col-md-12 form-group">
{users.map((user) => (
<React.Fragment key={user.key}>
<TextField
value={user}
onChange={(inputUser) => this.onChange(inputUser)}
/>
<button
type="button"
onClick={() => this.removeElement(user.key)}
disabled={users.length <= 1}
>
Remove
</button>
</React.Fragment>
))}
</div>
</div>
);
}
}
export default App;
// child component
import { Component } from "react";
class TextField extends Component {
handleChange = (ev) => {
const { name, value } = ev.target;
this.props.onChange({
...this.props.value,
[name]: value
});
};
render() {
const { value: user } = this.props;
return (
<>
<input
className="form-control"
name="name"
value={user.name}
onChange={this.handleChange}
placeholder="name"
type="text"
/>
<input
className="form-control"
name="email"
value={user.email}
onChange={this.handleChange}
placeholder="email"
type="text"
/>
<input
className="form-control"
name="phone"
value={user.phone}
onChange={this.handleChange}
placeholder="phone"
type="text"
/>
</>
);
}
}
export default TextField;
You can also check the code in codesandbox link below.
https://codesandbox.io/s/suspicious-heisenberg-xzchm
It was a little difficult to write down every detail of how to generate what you want. So I find it much easier to ready a stackblitz link for you to see how is it going to do this and the link is ready below:
generating a dynamic div adding and removing by handling inputs state value
const { Component } = React;
class Example extends Component {
constructor(props) {
super();
// The only state in the main component
// is whether the form is visible or not
this.state = { visible: false };
}
addForm = () => {
this.setState({ visible: true });
}
removeForm = () => {
this.setState({ visible: false });
}
handleSubmit = (form) => {
console.log(form);
}
render() {
const { visible } = this.state;
const { config } = this.props;
return (
<div>
<button
type="button"
onClick={this.addForm}
>Add form
</button>
{visible && (
<Form
config={config}
handleSubmit={this.handleSubmit}
handleClose={this.removeForm}
/>
)}
</div>
);
}
};
class Form extends Component {
constructor(props) {
super();
this.state = props.config.reduce((acc, c) => {
return { ...acc, [c.name]: '' };
}, {});
}
handleChange = (e) => {
const { name, value } = e.target;
this.setState({ [name]: value });
}
handleSubmit = () => {
this.props.handleSubmit(this.state);
}
render() {
const { name, email, phone } = this.state;
const { handleClose, config } = this.props;
return (
<div onChange={this.handleChange}>
{config.map(input => {
const { id, name, type, required } = input;
return (
<div>
<label>{name}</label>
<input key={id} name={name} type={type} required={required} />
</div>
)
})}
<button type="button" onClick={this.handleSubmit}>Submit form</button>
<button type="button" onClick={handleClose}>Remove form</button>
</div>
);
}
}
const config = [
{ id: 1, name: 'name', type: 'text', required: true },
{ id: 2, name: 'email', type: 'email', required: true },
{ id: 3, name: 'phone', type: 'phone', required: true }
];
ReactDOM.render(
<Example config={config} />,
document.getElementById('react')
);
input { display: block; }
label { text-transform: capitalize; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

net::ERR_FILE_NOT_FOUND - React image error

class SingleProduct extends React.Component {
constructor(props) {
super(props);
this.state = {
edit: false,
name: "",
imageUrl: null,
price: 0,
description: "",
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.onImageChange = this.onImageChange.bind(this);
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value,
});
}
onImageChange = (event) => {
if (event.target.files && event.target.files[0]) {
let image = event.target.files[0];
console.log(image.src);
this.setState({
imageUrl: URL.createObjectURL(image),
});
}
};
handleSubmit(event) {
event.preventDefault();
console.log(this.props.cocktail);
this.props.updateCocktail({ ...this.props.cocktail, ...this.state });
this.setState({
edit: false,
});
}
render() {
const { cocktail, isAdmin } = this.props;
const { edit, name, price, description, imageUrl } = this.state;
const { handleChange, handleSubmit, onImageChange } = this;
return (
<div>
{isAdmin && (
<button
onClick={() =>
this.setState((prevState) => ({ edit: !prevState.edit }))
}
>
Edit Cocktail
</button>
)}
{edit ? (
<form>
<label>
Name:
<input
type="text"
name="name"
onChange={handleChange}
value={name}
/>
</label>
<label>
Upload Image:
<input type="file" name="imageUrl" onChange={onImageChange} />
<img src={imageUrl} />
</label>
<label>
Description:
<input
type="text"
name="description"
onChange={handleChange}
value={description}
/>
</label>
<label>
Price:
<input
type="text"
name="price"
onChange={handleChange}
value={price}
/>
</label>
<button type="submit" onClick={(event) => handleSubmit(event)}>
Submit
</button>
</form>
) : (.....stuff)}
</div>
);
}
}
I am attempting to a "file" button in my form and it does allow me to successfully add image and it displays that change in the backend. However, once I reload the page, I am thrown this error "GET blob:http://localhost:3000/3f9fwf19-c526-4404-bb-20a433542ed net::ERR_FILE_NOT_FOUND" and the image doesn't render.

React error: Cannot read property 'users' of undefined

I'm trying to run this code (picked up from some source) where inputs are created dynamically and values are recorded on submit.
I'm getting this error:
Cannot read property 'users' of undefined while calling createUI.
Can someone help me here, please?
import React, { useState } from "react";
import ReactDOM from "react-dom";
export default function App() {
const [state, setState] = useState({
users: [{ firstName: "", lastName: "" }]
});
const addClick = () => {
setState(prevState => {
users: [...prevState.users, { firstName: "", lastName: "" }];
});
};
const createUI = () => {
state.users.map((el, i) => {
return (
<div key={i}>
<input
placeholder="First Name"
name="firstName"
value={el.firstName || ""}
onChange={handleChange}
/>
<input
placeholder="Last Name"
name="lastName"
value={el.lastName || ""}
onChange={handleChange}
/>
<input type="button" value="remove" onClick={removeClick} />
</div>
);
});
};
const handleChange = (i, e) => {
const { name, value } = e.target;
let users = [...state.users];
users[i] = { ...users[i], [name]: value };
setState({ users });
};
const removeClick = i => {
let users = [...state.users];
users.splice(i, 1);
setState({ users });
};
const handleSubmit = event => {
alert("A name was submitted: " + JSON.stringify(this.state.users));
event.preventDefault();
};
return (
<form onSubmit={handleSubmit}>
{createUI()}
<input type="button" value="add more" onClick={addClick()} />
<input type="submit" value="Submit" />
</form>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
// const rootElement = document.getElementById("root");
// ReactDOM.render(<App />, rootElement)
Sandbox here ->
https://codesandbox.io/s/dynamic-fields-23cw4?fontsize=14&hidenavigation=1&theme=dark
The reason for that error is the following line:
<input type="button" value="add more" onClick={addClick()} />
Technically you are calling the addClick function which changes the value of your state object. The solution which works fine is the following:
<input type="button" value="add more" onClick={() => addClick()} />
Or shorter way:
<input type="button" value="add more" onClick={addClick} />
I hope that helps!
There were 3 issues with your code,
you executed your onclick handler, addClick which triggered inifinite loop
createUI method did not return the array of created components
addClick function's setState syntax was not correct.
const {useState} = React;
function App() {
const [state, setState] = useState({
users: [{ firstName: "", lastName: "" }]
});
const addClick = () => {
setState(prevState => {
return { users: [...prevState.users, { firstName: "", lastName: "" }] };
});
};
const createUI = () => {
return state.users.map((el, i) => {
return (
<div key={i}>
<input
placeholder="First Name"
name="firstName"
value={el.firstName || ""}
onChange={(e)=>handleChange(e, i)}
/>
<input
placeholder="Last Name"
name="lastName"
value={el.lastName || ""}
onChange={(e)=>handleChange(e, i)}
/>
<input type="button" value="remove" onClick={removeClick} />
</div>
);
});
};
const handleChange = (e, i) => {
const { name, value } = e.target;
let users = [...state.users];
users[i] = { ...users[i], [name]: value };
setState({ users });
};
const removeClick = i => {
let users = [...state.users];
users.splice(i, 1);
setState({ users });
};
const handleSubmit = event => {
alert("A name was submitted: " + JSON.stringify(this.state.users));
event.preventDefault();
};
return (
<form onSubmit={handleSubmit}>
{createUI()}
<input type="button" value="add more" onClick={addClick} />
<input type="submit" value="Submit" />
</form>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
In addition to #norbiial's answer which should be the accepted answer: Your addClick function is incorrect. Your setState call is not returning anything which means as soon as you click the add button it will break again.
Change to this:
const addClick = () => {
setState(prevState => ({
users: [...prevState.users, { firstName: "", lastName: "" }]
}));
};
The same issue will be seen in createUI.
Error 1:
if you are returning an Object without return statement it should be wrapped in a bracket
const addClick = () => {
setState(prevState => ({
users: [...prevState.users, { firstName: "", lastName: "" }];
}));
};
Error 2:
Missing return statement,
const createUI = () => {
return state.users.map((el, i) => {
return (
<div key={i}>
<input
placeholder="First Name"
name="firstName"
value={el.firstName || ""}
onChange={handleChange}
/>
<input
placeholder="Last Name"
name="lastName"
value={el.lastName || ""}
onChange={handleChange}
/>
<input type="button" value="remove" onClick={removeClick} />
</div>
);
});
};
Error 3:
onClick should have a function, but you are setting a value returned from addClick which is undefined
...
<input type="button" value="add more" onClick={addClick} />
...

How to write a generic method to handle multiple state changes in React

I'm building an exercise tracker app in React.
Right now, I'm building the CreateExercise component to submit a form, so I need to update the states of each value. In order to do so, I created methods to handle those changes (onChangeUsername, onChangeDescription, onChangeDuration etc...) but I don't really like to repeat methods like this.
How to write a more generic method to handle this task ?
class CreateExercise extends Component {
constructor(props) {
super(props);
this.state = {
username: '',
description: '',
duration: 0,
date: new Date(),
users: []
}
}
onChangeUsername = (e) => {
this.setState({
username: e.target.value
});
}
onChangeDescription = (e) => {
this.setState({
description: e.target.value
});
}
onChangeDuration = (e) => {
this.setState({
duration: e.target.value
});
}
onChangeDate = (date) => {
this.setState({
date: date
});
}
onSubmit = (e) => {
e.preventDefault();
const exercise = {
username: this.state.username,
description: this.state.description,
duration: this.state.duration,
date: this.state.date
}
console.log(exercise);
window.location = '/';
}
render() {
return(
<div>
<h3>Create New Exercise Log</h3>
<form onSubmit={ this.onSubmit }>
<div className='form-group'>
<label>Username:</label>
<select
ref='userInput'
required
className='form-control'
value={ this.state.username }
onChange={ this.onChangeUsername }
>
{ this.state.users.map((user) => (
<option key={user} value={user}>{user}</option>
))
}
</select>
</div>
<div className='form-group'>
<label>Description:</label>
<input
type='text'
required
className='form-control'
value={ this.state.description }
onChange={ this.onChangeDescription}
/>
</div>
<div className='form-group'>
<label>Duration:</label>
<input
type='text'
className='form-control'
value={ this.state.duration }
onChange={ this.onChangeDuration }
/>
</div>
<div className='form-group'>
<label>Date:</label>
<div>
<DatePicker
selected={ this.state.date }
onChange={ this.onChangeDate }
/>
</div>
</div>
<div className='form-groupe'>
<input
type='submit'
value='Create Exercise Log'
className='btn btn-primary'
/>
</div>
</form>
</div>
);
}
}
export default CreateExercise;
Using partial application, create a function in your component that takes a field name, and returns a function that sets the state:
onChangeValue = field => e => {
this.setState({
[field]: e.target.value
});
};
Usage:
onChangeUsername = onChangeValue('username');
onChangeDescription = onChangeValue('description');
onChangeDuration = onChangeValue('duration');
You extend the idea further to support the onChangeDate as well:
onChangeValue = (field, valueTransformer = e => e.target.value) => e => {
this.setState({
[field]: valueTransformer(e.target.value)
});
};
This doesn't change the other on functions, since the default is to get e.target.value. To use onChangeDate we can now change the valueTransformer:
onChangeDate = onChangeValue('date', v => v);
You can define name for the HTML element, and use that to set value:
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
corresponding JSX element:
<input
type="text"
name="description"
required
className="form-control"
value={this.state.description}
onChange={this.onChange}
/>

Can someone help me how to render immediately after the put and delete request

class App extends Component {
constructor() {
super();
this.state = {
currentProduct: null,
items: [],
};
this.handlepostSubmit= this.handlepostSubmit.bind(this);
}
componentDidMount() {
axios.get('http://localhost:3000/api/v1/products.json')
.then(res => {
const items = res.data;
this.setState({ items });
})}
handlepostSubmit = event => {
event.preventDefault();
const product = {
name: event.target[0].value,
style_no: event.target[1].value,
color: event.target[2].value,
material: event.target[3].value,
origin: event.target[4].value,
};
let token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
axios.defaults.headers.common['X-CSRF-Token'] = token;
axios.defaults.headers.common['Accept'] = 'application/json'
axios.put(`http://localhost:3000/api/v1/products/${this.state.currentProduct.id}`, {product})
.then(res => {
console.log(res);
console.log(res.data);
})
}
handleSubmit = event => {
event.preventDefault();
axios.delete
(`http://localhost:3000/api/v1/products/${this.state.currentProduct.id}`)
.then(res => {
})
}
render() {
const products = []
this.state.items.map(person =>
products.push(person))
return (
<div>
<div>
<Sidebar products={products} onSelect={product => this.setState({currentProduct: product})}/>
</div>
<div>
<Form product={this.state.currentProduct} />
</div>
<div>
<form onSubmit={this.handlepostSubmit}>
<label>Name:<input type="text" /></label>
<label>Style_no:<input type="text"/></label>
<label>Color:<input type="text" /></label>
<label>material<input type="text" /></label>
<label>Orgin<input type="text" /></label>
<input type="submit" value="Edit" />
</form>
</div>
<button onClick={this.handleSubmit}>Delete</button>
</div>
);}}
export default App
Right now, I am facing difficulties with how to render the component after the put and delete request. In the code above, after I click the edit and delete button, it does not render on the page immediately. I have to refresh the page to get the new information. Can someone give me information how to do this kind of stuff.
// APP COMPONENT
import React, { Component } from 'react';
import axios from 'axios';
import Sidebar from './sidebar';
import Form from './form';
class App extends Component {
constructor(props) {
super(props);
this.state = {
currentProduct: null,
products: [],
name: '',
styleNo: '',
color: '',
material: '',
origin: '',
};
this.handlepostSubmit = this.handlepostSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleProductSelected = this.handleProductSelected.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}
// forceUpdateHandler(){
// this.forceUpdate();
// };
handleChange(e) {
const name = e.target.name;
this.setState({
[name]: e.target.value,
});
}
componentDidMount() {
axios.get('https://jsonplaceholder.typicode.com/posts').then(res => {
const items = res.data;
console.log(items);
this.setState({ products: items });
});
// http://localhost:3000/api/v1/products.json
}
handlepostSubmit(e) {
e.preventDefault();
const { name, styleNo, color, material, origin } = this.state;
console.log('selected name ', name);
const product = {
name,
style_no: styleNo,
color,
material,
origin,
};
console.log(product);
// let token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
// axios.defaults.headers.common['X-CSRF-Token'] = token;
// axios.defaults.headers.common['Accept'] = 'application/json'
// axios.put(`http://localhost:3000/api/v1/products/${this.state.currentProduct.id}`, {product})
// .then(res => {
// })
}
handleDelete(e) {
e.preventDefault();
console.log('on delete');
// axios.delete(`http://localhost:3000/api/v1/products/${this.state.currentProduct.id}`)
// .then(res => {
// })
}
// forceUpdate =event=>{
// location.reload(true);
// }
handleProductSelected(product) {
this.setState({
currentProduct: product,
});
}
render() {
const { products } = this.state;
return (
<div>
<div>
<Form product={this.state.currentProduct} />
</div>
<div>
<form onSubmit={this.handlepostSubmit}>
<label>
Name:
<input type="text" name="name" onChange={this.handleChange} />
</label>
<label>
Style_no:
<input type="text" name="styleNo" onChange={this.handleChange} />
</label>
<label>
Color:
<input type="text" name="color" onChange={this.handleChange} />
</label>
<label>
material
<input type="text" name="material" onChange={this.handleChange} />
</label>
<label>
Orgin
<input type="text" name="origin" onChange={this.handleChange} />
</label>
<input type="submit" value="Edit" onChange={this.handleChange} />
</form>
</div>
<div>
<button onClick={this.handleDelete}>Delete</button>
</div>
<div>
<Sidebar products={products} onSelect={this.handleProductSelected} />
</div>
</div>`enter code here`
);
}
}
export default App;
//Sidebar Component
import React from 'react';
class SideBar extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(product) {
const { onSelect } = this.props;
onSelect(product);
}
render() {
const { products } = this.props;
return products.map(product => {
// let boundItemClick = onItemClick.bind(this, x);
return (
<li key={product.id} onClick={() => this.handleClick(product)}>
<p> {product.id} </p>
{/* <p> {product.style_no}</p>
<p> {product.color}</p> */}
</li>
);
});
}
}
export default SideBar;
import React from 'react';
class Form extends React.Component {
render() {
const { product } = this.props;
return (
<section id="product">
<p>selected product: {product ? product.id : 'no product'} </p>
</section>
);
}
}
export default Form;

Categories