First am pretty new to react.
Am trying to change state of form inputs as follows
constructor(props) {
super(props);
this.state = {
pwd:'',
email:'',
value:''
};
this.handleEmailChange = this.handleEmailChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
}
handlePasswordChange(event){
//this.setState({value: event.target.value});//Works
this.setState({pwd: event.target.pwd});// Fails
}
My problem is I am not able to set the state of the password field and instead am getting a warning saying Warning: A component is changing a controlled input of type password to be uncontrolled
My render method is as bellow
render(){
return(
<div
className="container col-md-6 col-md-offset-3"
>
<Form horizontal onSubmit={this.handleSubmit}>
<FormGroup
controlId="formHorizontalEmail">
<Col componentClass={ControlLabel} sm={2}>
Email
</Col>
<Col sm={10}>
<FormControl type="email" placeholder="Email"
value={this.state.email} onChange={this.handleEmailChange}/>
</Col>
</FormGroup>
<FormGroup
controlId="formHorizontalPassword"
>
<Col componentClass={ControlLabel} sm={2}>
Password
</Col>
<Col sm={10}>
<FormControl type="password" placeholder="Password"
value={this.state.pwd} onChange={this.handlePasswordChange}
//if I change to value={this.state.value} it works
/>
</Col>
</FormGroup>
<FormGroup>
<Col smOffset={2} sm={10}>
<Checkbox>Remember me</Checkbox>
</Col>
</FormGroup>
<FormGroup>
<Col smOffset={2} sm={10}>
<Button type="submit">
Sign in
</Button>
</Col>
</FormGroup>
</Form>
</div>
);
}
Note: I have omitted some code that I think is not crucial.
Just change:
this.setState({pwd: event.target.pwd});// Fails
for:
this.setState({pwd: event.target.value});
The event has an attribute target which has an attribute value with the value of the field at that particular moment. Hence you should assign that value to the pwd state attribute that you are defining :)
Always remember that you are sending an object to the setState function. The key of that object is the one that you are defining (pwd). The value is just the thing that you assign to that key, it could be a number, a string... or the value of an object's attribute (like in this case the string that contains event.target.value).
I'll show you a little snippet that I'm using in production:
This is your state:
constructor(props) {
super(props);
this.state = {
pwd:'',
email:''
};
So, now you may want to build a form in order to change these values. I'd recommend to do so:
<input name="pwd" onChange={(e) => this.handleChange(e)} ...>
<input name="email" onChange={(e) => this.handleChange(e)} ...>
So now you can do so:
handleChange(e){
this.setState({[e.target.name]: e.target.value})
}
e.target.name takes the name of your input field (in that case: 'pwd' or 'email') and e.target.value takes its value.
When you're writing more complex forms, this can help you a lot!
Related
Creating a function that will update my state based to edit user profile information based on input submitted on a form.
My function is only updating the last input I entered in my form. Here is a snippet of my code
let { user,logOutUser,updateProfile } = useContext(AuthContext)
//store users in state
const[profileUser, setProfileUser] = useState({user})
//handle form submission
const handleSubmit = e => {
console.log(user)
const updatedProfile = {
username: profileUser.username,
email: profileUser.email,
first_name: profileUser.first_name,
last_name: profileUser.last_name,
city: profileUser.city,
country: profileUser.country
}
console.log(updatedProfile)
e.preventDefault();
}
and here's my form:
<Form>
<Row>
<Col className="pr-1" md="6">
<FormGroup>
<label>Username</label>
<Input
placeholder="Username"
type="text"
name="username"
onChange={ e => setProfileUser({'username': e.target.value}) }
/>
</FormGroup>
</Col>
<Col className="pr-1" md="6">
<FormGroup>
<label htmlFor="exampleInputEmail1">
Email address
</label>
<Input
placeholder="Email"
type="email"
name="email"
value={profileUser.email}
onChange={ e => setProfileUser({'email': e.target.value}) }
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col className="pr-1" md="6">
<FormGroup>
<label>First Name</label>
<Input
placeholder="Enter your first name"
type="text"
name="first_name"
onChange={ e => setProfileUser({'first_name': e.target.value}) }
/>
</FormGroup>
</Col>
<Col className="pr-1" md="6">
<FormGroup>
<label>Last Name</label>
<Input
placeholder="Enter your last name"
type="text"
name="last_name"
onChange={ e => setProfileUser({'last_name': e.target.value}) }
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col className="pr-1" md="6">
<FormGroup>
<label>City</label>
<Input
placeholder="Enter your city"
type="text"
name="city"
onChange={ e => setProfileUser({'city': e.target.value}) }
/>
</FormGroup>
</Col>
<Col className="pr-1" md="6">
<FormGroup>
<label>Country</label>
<Input
placeholder="Enter your country"
type="text"
name="country"
onChange={ e => setProfileUser({'country': e.target.value}) }
/>
</FormGroup>
</Col>
<div className="update ml-auto mr-auto">
<Button
className="btn-round"
color="primary"
type="submit"
onClick={handleSubmit}
>
Update Profile
</Button>
</div>
</Row>
</Form>
This is what I have in users:
bio: ""
city: ""
country: ""
exp: *****
first_name: ""
iat: *****
jti: "******"
last_name: ""
photo: "\"profile/2022/03/27/emmanuelpic.png\""
token_type: "access"
user_id: 1
username: "emmanuelS21"
When I console log updateProfile after submitting updated profile data, I am only getting the last input I entered in my form (ie. If I enter last_name, I only see this in my console log while everything else in my object is empty)
Each use of setProfileUser is overwriting the entire object with a new object that contains only one property:
onChange={ e => setProfileUser({'email': e.target.value}) }
You can destructure the current state to build the complete new state:
onChange={ e => setProfileUser({ ...profileUser, 'email': e.target.value}) }
This is notably different from the older setState used in class-based components. With setState the framework would automatically perform partial updates for you. But with the setter function in useState hooks, any update is complete as-is.
when you set the state must add rest of value to new state with {...rest}
onChange={ e => setProfileUser({...profileUser,'username': e.target.value}) }
I'm new to React and just started working with state so please bare with me. I also found a lot of similar questions but nothing that really addresses the following:
I have a reactstrap form that has disabled FormControls. When the user clicks the 'edit' button the FormControls need to be enabled. According to my knowledge, this should be simple with JSX but nothing I've tried has worked. It might just be a stupid implementation error on my side.
class UserProfile extends React.Component {
constructor(props) {
super(props);
this.state = {
editToggle: false,
userName: "Star Lord",
accTier: "Premium",
credit: "95 855 651",
vehicle: "The Milano",
contact: "Echoe Golf Oscar 12.465Ghz"
}
// This binding is necessary to make `this` work in the callback
this.editInputToggle = this.editInputToggle.bind(this);
}
editInputToggle() {
this.setState(prevState => ({
editToggle: !prevState.editToggle
}));
}
onValueChange = (e) => {
this.setState({ fullName: e.target.value });
};
render() {
const { editToggle } = this.state;
// We need give the components function a return statement.
return (
/* The Component can only return one parent element,
while parent elements can have many children */
<div className='profileDetails'>
{/* Bootstrap Form is used for the form
Bootstrap Button is used for the edit button */}
<Form id='formProfile'>
<Form.Group className="mb-3" controlId="formProfileDetails">
<Form.Label>US3RNAME:</Form.Label>
<Form.Control type="text" value={this.state.userName}
onChange={this.onValueChange} className='user-info' />
<Form.Label>ACC0uNT TI3R:</Form.Label>
<Form.Control disabled type="text" value={this.state.accTier} onChange={this.onValueChange} className='user-info' />
<Form.Label>CR3DiT:</Form.Label>
<Form.Control disabled type="text" value={this.state.credit} onChange={this.onValueChange} className='user-info' />
<Form.Label>R3GiSTERED VEHiCL3:</Form.Label>
<Form.Control disabled type="text" value={this.state.vehicle} onChange={this.onValueChange} className='user-info' />
<Form.Label>C0NTACT D3TAiLS:</Form.Label>
<Form.Control disabled type="text" value={this.state.contact} onChange={this.onValueChange} className='user-info' />
</Form.Group>
<Button variant="light" size="sm" className='p-2 m-4 headerBtn' onClick={ () => this.editInputToggle(editToggle) }>
Edit
</Button>
</Form>
</div>
);
}
}
What do I need to do to change "disabled" to ""?
For enabling the FormControl,
<Form.Control disabled={!this.state.editToggle} type="text" value={this.state.accTier} onChange={this.onValueChange} className='user-info' />
Try replacing "disabled" with this line: disabled={this.state.editToggle ? "true" : "false"}
The aim: Pass the value of state.TNC and state.promos into the emailjs.sendForm.
Submitted email should see 'true' if the box is checked, false if not.
I am lost for words as to what I need to google to find a resolution that involves semantic and emailjs...
Here is my code that I thought was going to do that for me.
value={this.state.promos}
value={this.state.TNC}
These are the states they should be returning as the values and being passed into the emailjs e.target
this.state = {
TNC: false,
promos: true,
};
The code for the two checkboxes, (I have tried them with and without the value={this.state.TNC})
<Form.Group widths="equal">
<Form.Field>
<Checkbox
label="I agree to the Terms and Conditions"
required
control={Checkbox}
data="TNC"
onChange={this.onToggle}
value={this.state.TNC}
/>
</Form.Field>
<Form.Field>
<Checkbox
label="Send me occasional updates and promotions"
defaultChecked
control={Checkbox}
data="promos"
value={this.state.promos}
onChange={this.onTogglePromos}
/>
</Form.Field>
</Form.Group>
Here is the full code, and you can find a semi-functional version of the form at https://test.ghostrez.net
import emailjs from "emailjs-com";
import { Component } from "react";
import { Button, Checkbox, Form, Input, TextArea } from "semantic-ui-react";
export default class ContactUs extends React.Component {
constructor(props) {
super(props);
this.state = {
TNC: false,
promos: true,
};
}
onToggle = () => {
const TNC = !this.state.TNC;
this.setState({ TNC });
};
onTogglePromos = () => {
const promos = !this.state.promos;
this.setState({ promos });
};
sendEmail = (e, props) => {
e.preventDefault();
if (this.state.TNC !== false) {
return emailjs
.sendForm("tester", "testiTemp", e.target, "user_EPYkKnHwiytfdolol565ljQTCbJkzO7YD")
.then(
(result) => {
alert("Email sent successfully!");
e.target.reset();
},
(error) => {
alert("Email send failed... :( I had one job...");
}
);
} else {
return alert(
"You need to accept the Terms and Conditions before proceeding."
);
}
};
render() {
return (
<Form onSubmit={this.sendEmail}>
<Form.Group widths="equal">
<Form.Field
id="firstName"
control={Input}
label="First name"
name="firstName"
placeholder="First name"
required
/>
<Form.Field
id="lastName"
name="lastName"
control={Input}
label="Last name"
placeholder="Last name"
/>
</Form.Group>
<Form.Group widths="equal">
<Form.Field
id="Email"
control={Input}
label="Email"
name="email"
placeholder="joe#schmoe.com"
required
/>
<Form.Field
id="Phone"
control={Input}
label="Phone"
name="phone"
placeholder="0469 420 689"
required
/>
</Form.Group>
<Form.Field
id="Message"
control={TextArea}
label="Message"
name="message"
placeholder="Message"
required
/>
<Form.Group widths="equal">
<Form.Field>
<Checkbox
label="I agree to the Terms and Conditions"
required
control={Checkbox}
data="TNC"
onChange={this.onToggle}
value={this.state.TNC}
/>
</Form.Field>
<Form.Field>
<Checkbox
label="Send me occasional updates and promotions"
defaultChecked
control={Checkbox}
data="promos"
value={this.state.promos}
onChange={this.onTogglePromos}
/>
</Form.Field>
</Form.Group>
<Form.Field
id="Submit"
control={Button}
type="submit"
value="submit"
positive
content="Submit"
/>
</Form>
);
}
}
Thank you for your help, I really appreciate it.
In order to check, the property is not value but checked, try with this :
<Checkbox
label="I agree to the Terms and Conditions"
required
control={Checkbox}
data="TNC"
onChange={this.onToggle}
checked={this.state.TNC}
/>
This the solution that worked for me, although it only displays if true (checkbox is checked)
I have added id value and value&checked both as (this.state.*state*)
My solution was as follows
<Form.Group widths="equal">
<Form.Field>
<Checkbox
id="Accept_TnCs"
label="I agree to the Terms and Conditions"
required
control={Checkbox}
name="TNC"
value={this.state.TNC}
checked={this.state.TNC}
onChange={this.onToggle}
/>
</Form.Field>
<Form.Field>
<Checkbox
id="Accept_Promos"
label="Send me occasional updates and promotions"
defaultChecked
control={Checkbox}
name="promos"
value={this.state.promos}
checked={this.state.promos}
onChange={this.onTogglePromos}
/>
</Form.Field>
</Form.Group>
So, this is my App.js file and the next picture is what I get when I hit submit. I want to get all the entered values to be printed on console but that's not happening.
I am also using Flask as backend and I want to get all these data into app.py so how to do that ?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
petalLen: "",
petalWid: "",
sepalLen: "",
sepalWid: "",
};
this.handleOnChange = this.handleOnChange.bind(this);
}
handleOnChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const data = new FormData(event);
for (let [key, value] of data.entries()) {
console.log(key, value);
}
}
render() {
return (
<div className="App">
<h1>Deploy Models for Humans </h1>
<Form>
<Container>
<Row className="Rr">
<Col>
<Form.Label>Petal Length</Form.Label>
<Form.Control
type="text"
name="petalLen"
value={this.state.petalLen}
onChange={this.handleOnChange}
placeholder="Petal Length"
/>
</Col>
<Col>
<Form.Group>
<Form.Label>Petal Width</Form.Label>
<Form.Control
type="text"
name="petalWid"
value={this.state.petalWid}
onChange={this.handleOnChange}
placeholder="Petal Width"
/>
</Form.Group>
</Col>
<Col>
<Form.Group>
<Form.Label>Sepal Length</Form.Label>
<Form.Control
type="text"
name="sepalLen"
value={this.state.sepalLen}
onChange={this.handleOnChange}
placeholder="Sepal Length"
/>
</Form.Group>
</Col>
<Col>
<Form.Group>
<Form.Label>Sepal Width</Form.Label>
<Form.Control
type="text"
name="sepalWid"
value={this.state.sepalWid}
onChange={this.handleOnChange}
placeholder="Sepal Width"
/>
</Form.Group>
</Col>
</Row>
<Button variant="primary" type="submit" onClick={this.handleSubmit}>
Submit
</Button>
</Container>
</Form>
</div>
);
}
}
After I hit submit :
I'm trying to create a dropdown select list that is dependent on it's parent list i.e Category and then a subcategory for a clothing catalogue. The plan is to then store that data in firestore but whenever i use map, I keep running into this error that tells me "Cannot read property 'map' of undefined". I've tried putting the map block in an if statement but that does'nt work either.
class Catalogue extends Component{
constructor(){
super();
this.state={
prodname:'',
prodprice:'',
prodcat:'',
prodsize:'',
proddetails:'',
selectedView:'Men'
};
}
updateInput = e => {
this.setState({
[e.target.name]: e.target.value
});
}
addProd = e => {
e.preventDefault();
const db = firebase.firestore();
const userRef = db.collection("Users").doc("User1").set({
prodname: this.state.prodname,
prodprice: this.state.prodprice,
prodcat: this.state.prodcat,
prodsize: this.state.prodsize,
proddetails: this.state.proddetails,
});
this.setState({
prodname:'',
prodprice:'',
prodcat:'',
prodsize:'',
proddetails:'',
selectedView:'Men'
});
};
render(){
//==================Subcategories Code====================//
const { selectedView } = this.state
const VIEWS = [
{
name: 'Men',
minor: ['Shirts', 'Pants']
}, {
name: 'Women',
minor: ['Shirt', 'Skirt']
}
]
const getMajorMethod = () => {
const view = VIEWS.filter(({name}) => name === selectedView)
return (
<div>
<select>
{view.minor.map(m => <option>{m}</option>)}
</select>
</div>
)
}
return(
<div id="container">
<Form onSubmit={this.addProd}>
<FormGroup row>
<Label for="prod_name" sm={2}>Product Name</Label>
<Col sm={10}>
<Input type="text" name="prodname" id="prod_name" onChange={this.updateInput} value={this.state.prodname}/>
</Col>
</FormGroup>
<FormGroup row>
<Label for="prod_price" sm={2}>Price Rs:</Label>
<Col sm={10}>
<Input type="number" name="prodprice" id="prod_price" onChange={this.updateInput} value={this.state.prodprice} />
</Col>
</FormGroup>
<FormGroup row>
<Label for="prod_cat" sm={2}>Category</Label>
<Col sm={10}>
<Input type="select" name="prodcat" id="prod_cat" onChange={this.updateInput} value={this.state.prodcat} >
<option disabled="disabled" value="">Select Category</option>
<option value="Men">Men</option>
<option value="Women">Women</option>
</Input>
</Col>
</FormGroup>
<FormGroup row>
<Label for="prod_subcat" sm={2}>Sub Category</Label>
<Col sm={10}>
<select onChange={(e) => this.setState({selectedView: e.target.value})}>
{VIEWS.map(({name}) => <option value={name}>{name}</option>)}
</select>
{getMajorMethod()}
</Col>
</FormGroup>
<FormGroup row>
<Label for="prod_size" sm={2}>Size</Label>
<Col sm={10}>
<Input type="select" name="prodsize" id="prod_size" onChange={this.updateInput} value={this.state.prodsize}>
<option disabled="disabled" value="">Select Size</option>
<option value="S">S</option>
<option value="M">M</option>
<option value="L">L</option>
<option value="XL">XL</option>
</Input>
</Col>
</FormGroup>
<FormGroup row>
<Label for="prod_details" sm={2}>Product Details</Label>
<Col sm={10}>
<Input type="textarea" name="proddetails" id="prod_details" onChange={this.updateInput} value={this.state.proddetails} />
</Col>
</FormGroup>
<FormGroup check row>
<Col sm={{ size: 10, offset: 2 }}>
<Button>Submit</Button>
</Col>
</FormGroup>
</Form>
</div>
);
}
}
export default Catalogue;
The array filter function returns an array, so view.minor is not valid, since view is an array.
You can use array.protoype.find instead to return the view object you want to access into and map the minor array of.
The find() method returns the value of the first element in the
provided array that satisfies the provided testing function.
It can return undefined if no element in the array is found, so you will want to do a null check and conditionally render the select and options only if view is a defined object.
const getMajorMethod = () => {
const view = VIEWS.find(({name}) => name === selectedView)
return view ? (
<div>
<select>
{view.minor.map(m => <option>{m}</option>)}
</select>
</div>
) : null
}
It is because the view here const view = VIEWS.filter(({name}) => name === selectedView)
contains only name and not minor. So when you try to get minor here {view.minor.map(m => <option>{m}</option>)} from view you are getting undefined