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.
Related
might seem awkward right, but i simply did equalize the value attribute of input tag into some random state. but i simply cant even type into the input. the input is supposed to be emptied after click but well, nothing is happening. (sorry if this question is asked before, im really going crazy and couldnt find anything on google which helps me)
import React from 'react';
import './App.css';
class App extends React.Component{
constructor(){
super()
this.state ={
address : "",
name:"",
main : {
},
// city:undefined,
inputval: "",
}
}
handleName = (event) => {
this.setState({name: event.target.value})
}
handleAdd = (event) => {
this.setState({address: event.target.value})
}
handleClick = (event) => {
event.preventDefault()
this.setState({main:{
address: this.state.address,
name: this.state.name,
}})
this.setState({inputval:""})
}
render(){
return(
<div>
<form>
<input value={this.state.inputval} type="text" onChange={(e) => {this.handleName(e)}}/>enter full name
<br/>
<input value={this.state.inputval} type="text" onChange={(e) => {this.handleAdd(e)}}/> enter adresss
<br/>
<button onClick={(e) => {this.handleClick(e)}}>Click me</button>
</form>
</div>
)
}
}
export default App;
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = {
address: "",
name: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const { name, value } = event.target;
this.setState({
[name]: value
});
}
handleSubmit(event) {
event.preventDefault();
alert("A name was submitted: " + this.state.name);
this.setState({
address: "",
name: ""
});
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
value={this.state.name}
name="name"
type="text"
onChange={this.handleChange}
/>
enter full name
<br />
<input
value={this.state.address}
name="address"
type="text"
onChange={this.handleChange}
/>{" "}
enter adresss
<br />
<input type="submit" value="Submit" />
</form>
</div>
);
}
}
export default App;
Add name attributes to write only one change handler. It makes it so easier. I hope it helps. Look I wrote again setState to reset after submitting
You are not changing inputval at all. If you want to reset the form after button change. Then below is the solution
import React from 'react';
import './App.css';
class App extends React.Component{
constructor(){
super()
this.state ={
address : "",
name:"",
main : {
},
// city:undefined,
inputval: "",
}
this.handleName = this.handleName.bind(this)
this.handleAdd = this.handleAdd.bind(this)
this.handleClick = this.handleClick.bind(this)
}
handleName = (event) => {
this.setState({name: event.target.value})
}
handleAdd = (event) => {
this.setState({address: event.target.value})
}
handleClick = (event) => {
event.preventDefault()
this.setState({main:{
address: this.state.address,
name: this.state.name,
}})
this.setState({
address: "",
name: ""
})
}
render(){
return(
<div>
<form>
<input value={this.state.name} type="text" onChange={(e) => {this.handleName(e)}}/>enter full name
<br/>
<input value={this.state.address} type="text" onChange={(e) => {this.handleAdd(e)}}/> enter adresss
<br/>
<button onClick={(e) => {this.handleClick(e)}}>Click me</button>
</form>
</div>
)
}
}
export default App;
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}
/>
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;
While running my app, and when trying to update state with some form values the following error message appears:
"Uncaught TypeError: this.setState is not a function"
LoginForm.onChange
src/components/forms/LoginForm.js:21
18 | }
19 |
20 | onChange = e => {
> 21 | this.setState({
| ^ 22 | data: { ...this.state.data, [e.target.name]: e.target.value }
23 | });
24 | }
Added binding in constructor to onChange (this was not there before), but this does not resolve the problem.
this.onChange = this.onChange.bind(this);
I'm using: react: "^16.8.6"
Here is the component code:
import React from "react";
import { Form, Button } from "semantic-ui-react";
import Validator from "validator";
import InlineError from "../messages/InlineError"
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data: {
email: "",
password: ""
},
loading: false,
errors: {}
};
this.onChange = this.onChange.bind(this);
}
onChange = e => {
this.setState({
data: { ...this.state.data, [e.target.name]: e.target.value }
});
}
onSubmit = () => {
const errors = this.validate(this.state.data);
this.setState = ({ errors });
};
validate = (data) => {
const errors = {};
if (!Validator.isEmail(data.email)) errors.email = "Invalid email."
if (!data.password) errors.password = "Cannot be blank.";
return errors;
};
render() {
const { data, errors } = this.state;
return (
<Form onSubmit={this.onSubmit}>
<Form.Field>
<label htmlFor="email">Email</label>
<input
type="email"
id="email"
name="email"
placeholder="me#example.com"
value={data.email}
onChange={this.onChange}
/>
</Form.Field>
{errors.email && <InlineError text={errors.email} />}
<Form.Field>
<label htmlFor="password">Password</label>
<input
type="password"
id="password"
name="password"
placeholder="Enter your password"
value={data.password}
onChange={this.onChange}
/>
{errors.password && <InlineError text={errors.password} />}
</Form.Field>
<Button primary>Login</Button>
</Form>
);
}
}
export default LoginForm;
Everything is right with the code except onChange handler just small
modification to your onChange handler
onChange = e => {
const target = e.target;
const name = target.name;
this.setState({
...this.state,
data: {
...this.state.data,
[name]: target.value
}
});
};
Sorry I ignored onSubmit it should be like this
onSubmit = () => {
const errors = this.validate(this.state.data);
this.setState({ errors });
};
And This should work !!
Make sure Component Look Like this
import React from "react";
import { Form, Button } from "semantic-ui-react";
import Validator from "validator";
import InlineError from "../messages/InlineError";
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data: {
email: "",
password: ""
},
loading: false,
errors: {}
};
}
onChange = e => {
const target = e.target;
const name = target.name;
this.setState({
...this.state,
data: {
...this.state.data,
[name]: target.value
}
});
};
onSubmit = () => {
const errors = this.validate(this.state.data);
this.setState({ errors });
};
validate = data => {
const errors = {};
if (!Validator.isEmail(data.email)) errors.email = "Invalid email.";
if (!data.password) errors.password = "Cannot be blank.";
return errors;
};
render() {
const { data, errors } = this.state;
return (
<Form onSubmit={this.onSubmit}>
<Form.Field>
<label htmlFor="email">Email</label>
<input
type="email"
id="email"
name="email"
placeholder="me#example.com"
value={data.email}
onChange={this.onChange}
/>
</Form.Field>
{errors.email && <InlineError text={errors.email} />}
<Form.Field>
<label htmlFor="password">Password</label>
<input
type="password"
id="password"
name="password"
placeholder="Enter your password"
value={data.password}
onChange={this.onChange}
/>
{errors.password && <InlineError text={errors.password} />}
</Form.Field>
<Button primary>Login</Button>
</Form>
);
}
}
export default LoginForm;
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.