React Select doesn't update value on clicking option - javascript

I have a React Select form, with options loaded after an API call. The initial state value of workshop is set, and it updates after an option is clicked in the form. However, the Select's view does not update. What is more, when the form is submitted, the workshop is successfully saved into the database. What should I do ?
renderForm() {
return (
<section className="col-md-12 col-sm-12">
<form className="col-md-12 col-sm-12"
onSubmit={ this.handleSubmit }>
// other form-groups
<div className="form-group">
<label>
Region:
<input className="form-control"
type="text"
value={ this.state.value }
onChange={ this.handleRegionChange } required />
</label>
</div>
<div className="form-group">
<label>
Workshop:
</label>
<Select name="form-field-workshop"
value={ this.state.workshop }
onChange={ this.handleWorkshopChange }
options={ this.renderFormWorkshops() }
clearable={ false }
searchable={ false }
required />
</div>
<input className="btn btn-default"
type="submit"
value="Submit" />
</form>
</section>
);
}
// handles the change of state when an option is selected
handleWorkshopChange(value) {
this.setState({
workshop: value.label
});
}
// displays the options in the Select form
renderFormWorkshops() {
return _.map(this.props.workshops.workshops, (it) => {
return (
{ value: it.id, label: it.name }
);
});
}

handleWorkshopChange(value) {
this.setState({
workshop: value.value
});
}

Do you have it setup correctly in your constructor? There are likely some context issues happening here, this is the correct form to bind context:
constructor(props) {
super(props);
this.handleWorkshopChange = this.handleWorkshopChange.bind(this);
}
If you aren't using arrow functions, you need to bind context for situations that rely on using this methods.
Also, you have a stray parentheses here: value={ this.state.workshop) }

Related

Pass data between two react components in MERN stack

I am trying to build an E commerce web app where I handle the payments. First I need to take shipping information. I have successfully inserted data into mongo but I could not pass the data into another js right away from a single click.
Here is my create address page.
import React, { Component } from 'react'
import '../App.css'
import axios from 'axios'
export default class CreateAddress extends Component {
constructor(props) {
super(props);
this.state = {
address: "",
city: "",
phoneNo:"",
postalCode: "",
country: ""
}
}
handleInputChange = (e)=>{
const {name,value} = e.target;
this.setState({
...this.state,
[name]:value
})
}
onSubmit = (e)=>{
e.preventDefault();
const {address,city,phoneNo,postalCode,country} = this.state;
const data = {
address: address,
city: city,
phoneNo: phoneNo,
postalCode: postalCode,
country: country
}
console.log(data)
axios.post("http://localhost:5000/address/save",data).then((res)=>{
if(res.data.success){
this.setState(
{address: "",
city: "",
phoneNo:"",
postalCode: "",
country: ""}
)
alert("Shipping info added successfully");
}
})
}
render() {
return (
<div className="row wrapper">
<div className="col-10 col-lg-5">
<form className="shadow-lg" >
<h1 className="mb-4">Shipping Info</h1>
<div className="form-group">
<label htmlFor="address_field">Address</label>
<input
type="text"
id="address_field"
className="form-control"
name='address'
value={this.state.address}
onChange={this.handleInputChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="city_field">City</label>
<input
type="text"
id="city_field"
className="form-control"
name='city'
value={this.state.city}
onChange={this.handleInputChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="phone_field">Phone No</label>
<input
type="phone"
id="phone_field"
className="form-control"
name='phoneNo'
value={this.state.phoneNo}
onChange={this.handleInputChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="postal_code_field">Postal Code</label>
<input
type="number"
id="postal_code_field"
className="form-control"
name='postalCode'
value={this.state.postalCode}
onChange={this.handleInputChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="country_field">Country</label>
<input
type = "text"
id="country_field"
className="form-control"
name='country'
value={this.state.country}
onChange={this.handleInputChange}
required
/>
</div>
<button
id="shipping_btn"
type="submit"
className="btn btn-block py-3"
onClick={this.onSubmit}
>
SAVE
</button>
<button id="shipping_btn" type="submit" className = "btn btn-block py-3"><a href = "/confirm" style={{textDecoration:'none',color:'white'}}>PROCEED</a></button>
</form>
</div>
</div>
)
}
}
Once I clicked the PROCEED button the data should direct into /confirm page
You can use react-router to move between different routes in React. Also, in your code when you are sending a post request on onSubmit method, you are clearing the state information, which I think needs to be handled in the confirm page since you need the data in that page also.
Here's a codesandbox demonstrating how you can send the information to another page, using react-router. I've used the functional components, but the concepts works for the class based components also.
note: also you should use onSubmit handler of the form to submit values rather than using the onClick method of the button. Otherwise you force users to click the button to submit the form.
You can use history API to pass data as a URL and grab it into confirm page.
history.push(`/confirmPage?city=${city}&postalCode=${postalCode}`)
in confirmPage.js you will get that data as props
export default class ConfirmPage extends Component{
render(){
const {city, postalCode } = this.props.location.query;
return (
<div>{postalCode}</div>
)
}

How can I force re-render input fields in a form in React?

I am trying to create a form where the user can edit the information of a contact from a database and then save those changes. The form correctly loads and saves the information from the database, but when componentDidMount() loads the current information into the form fields, the fields don't re-render, causing both the template text (ie. Name, Email, etc) and the information loaded from the database to display on top of each other. Clicking any of the input fields causes the field that was clicked to render properly with the text displaying above the input field, rather than over the loaded text.
How can I force the form to rerender each field after the data has been loaded properly in componentDidMount()? I've tried forceUpdate() but it didn't work, and I haven't been able to find anyone else with this issue. I suspect it has something to do with me using the bootstrap styles wrong, but even after reading all of bootstrap's documentation I couldn't find anything related to my issue.
Here are a couple of screenshots to show the issue.
The form right after loading
The form after clicking the 'Name' field
Here's the relevant code for the component.
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
role: "",
phone: "",
errors: {}
}
}
// Initializer: Copy contact's current data to state
componentDidMount() {
axios.get("/api/contacts/get/" + this.props.match.params.id)
.then(res => {
this.setState({ name: res.data.name });
this.setState({ email: res.data.email });
this.setState({ role: res.data.role });
this.setState({ phone: res.data.phone });
})
.catch(err => console.log(err));
this.forceUpdate();
}
// Change handler: Modify values when changed
onChange = e => {
this.setState({ [e.target.id]: e.target.value });
}
// Submit handler: Save changes to database
onSubmit = e => {
e.preventDefault();
const contact = {
name: this.state.name,
email: this.state.email,
role: this.state.role,
phone: stripNumber(this.state.phone)
};
// Post modified contact to database, then navigate back to Manage Contacts Dashboard
axios.post("/api/admin/contacts/update/" + this.props.match.params.id, contact);
window.location = PREVIOUS_URL;
}
render() {
const { errors } = this.state;
return (
<div>
<Link to={PREVIOUS_URL} className="btn-flat waves-effect">
<i className="material-icons left">keyboard_backspace</i> Back to Manage Contacts
</Link>
<h3>Edit contact</h3>
<form noValidate onSubmit={this.onSubmit}>
<div className="input-field col s12">
<input
onChange={this.onChange}
value={this.state.name}
error={errors.name}
id="name"
type="text"
className={classnames("", { invalid: errors.name })}
/>
<label htmlFor="name">Name</label>
<span className="red-text">{errors.name}</span>
</div>
<div className="input-field col s12">
<input
onChange={this.onChange}
value={this.state.email}
error={errors.email}
id="email"
type="email"
className={classnames("", { invalid: errors.email || errors.emailnotfound })}
/>
<label htmlFor="email">Email</label>
<span className="red-text">{errors.email}{errors.emailnotfound}</span>
</div>
<div className="input-field col s12">
<input
onChange={this.onChange}
value={this.state.role}
error={errors.role}
id="role"
type="text"
className={classnames("", { invalid: errors.role })}
/>
<label htmlFor="role">Role</label>
<span className="red-text">{errors.role}</span>
</div>
<div className="input-field col s12">
<input
onChange={this.onChange}
value={this.state.phone}
error={errors.phone}
id="phone"
type="tel"
className={classnames("", { invalid: errors.phone })}
/>
<label htmlFor="phone">Phone Number</label>
<span className="red-text">{errors.phone}</span>
</div>
<div className="form-group">
<input type="submit" value="Submit changes" className="btn btn-primary" />
<Link to={PREVIOUS_URL} className="btn btn-danger"> Cancel </Link>
</div>
</form>
</div>
)
}
}
Have you tried doing the data fetch inside componentWillMount()?

ReactJS event.target.value returns as undefined

I've made a form in ReactJS with one text input and when it submits I want to get its value and put it into a variable. But when I console.log() it returns as undefined. How do I fix this? Here is my code.
class App extends Component {
state = {
todoTitle: ""
};
render() {
return (
<div>
<center>
<form
onSubmit={(event) => {
event.preventDefault();
this.setState(todoTitle: event.target.value,);
console.log(this.state.todoTitle); // Returns "undefined"
}}
>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
style={{ width: "400px", height: "50px" }}
/>
<input
type="submit"
value="Submit"
id="submitButton"
></input>
</form>
</center>
}
}
}
You need to either make a controlled input or useRef for un-controlled input for the React to keep track of your todoTitle state.
To make a controlled input, you will need to use onChange event and a value={this.state.todoTitle} property.
Also on your form, it is best to add an onSubmit event. There is however an option to set the submit on the form submit button also. In that case we need to use onClick={this.handleSubmit} as follows <input type="submit" value="Submit" id="submitButton" onClick={this.handleSubmit} />.
The below code will work for you:
class Form extends React.Component {
state = {
todoTitle: "",
};
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state.todoTitle);
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
style={{ width: "400px", height: "50px" }}
value={this.state.todoTitle}
onChange={(e) => this.setState({ todoTitle: e.target.value })}
/>
<input type="submit" value="Submit" id="submitButton" />
</form>
</div>
);
}
}
You can modify your app a bit to get the value on onChange of input textfield, and then store it in the array in case of below example:
export default class App extends React.Component {
state = {
todoTitle: "",
todoList: []
};
render() {
return (
<div>
<center>
<form
onSubmit={event => {
event.preventDefault();
this.setState(
{
todoList: [...this.state.todoList, this.state.todoTitle]
},
() => {
console.log(this.state.todoList);
}
);
}}
>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
onChange={event => {
this.setState({ todoTitle: event.target.value });
console.log(event.target.value);
}}
style={{ width: "400px", height: "50px" }}
/>
<input type="submit" value="Submit" id="submitButton" />
</form>
</center>
</div>
);
}
}
Full app here: Stackblitz
There are a few other errors with your code, but I will just answer your question.
setState triggers a re-render, so your state isn't available to log until the next time it runs. You can just log what you put in setState.
console.log(event.target.value);
This question has more info.
setState doesn't update the state immediately
Also, you can do a callback.
this.setState({ todoTitle: event.target.value }, () =>
console.log(this.state.todoTitle)
);
Try this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = { todoTitle: "" };
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
event.preventDefault();
this.setState({ todoTitle: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
console.log(this.state.todoTitle);
}
render() {
return (
<div>
<center>
<form onSubmit={this.handleSubmit}>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
style={{ width: "400px", height: "50px" }}
onChange={this.handleChange}
/>
<input type="submit" value="Submit" id="submitButton" />
</form>
</center>
</div>
);
}
}
This will change the state on input changes and then logs on submit the state. An alternative would be to just get the input element and its value via getElementById or something similar in React.
Your code was also not very well formatted and a lot of closing tags missed.
Read more here:
Get form data in ReactJS

Render the form input binding from external function in react

I am trying to bind the input from the function, as per the below code
class ProfessionalLearningAction extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.ensureDataFetched();
}
handleChange(e) {
let change = {}
change[e.target.name] = e.target.value
this.setState(change)
}
render() {
return (
<div className="container">
<h1>Edit/Add Professional Learning</h1>
<p>This component demonstrates Add/Edit data from the server and working with URL parameters.</p>
<br /><br />
{renderProfessionalLearningTable(this.props)}
</div>
);
}
}
function renderProfessionalLearningTable(props) {
return (
<form className="container">
<div className="form-row">
<div className="form-group col-sm-6">
<label>Course Name *</label>
<input type="text" className="form-control" value={props.professionalLearnings.courseName || ''} onChange={ props.handleChange }
aria-describedby="Course Name" placeholder="Enter a course name" />
</div>
</div >
</form >
);
}
Keep getting the error
Failed prop type: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.
Since I know from the error message that I need to define handlechange event. I tried the below code
<input type="text" className="form-control" value={props.professionalLearnings.courseName || ''} onChange={this.handleChange}
aria-describedby="Course Name" placeholder="Enter a course name" />
Since I know it is a function call which is external to the class. How can I fix this error?
Its because you don't pass onchange props. And make sure whenever you made a component it should start with Capital Name(ReactJS component names must begin with capital letters?).
class ProfessionalLearningAction extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.ensureDataFetched();
}
handleChange(e) {
let change = {}
change[e.target.name] = e.target.value
this.setState(change)
}
render() {
return (
<div className="container">
<h1>Edit/Add Professional Learning</h1>
<p>This component demonstrates Add/Edit data from the server and working with URL parameters.</p>
<br /><br />
<RenderProfessionalLearningTable {...this.props} handleChange={this.handleChange}/> //Pass the handlechange component
</div>
);
}
}
function RenderProfessionalLearningTable(props) {
return (
<form className="container">
<div className="form-row">
<div className="form-group col-sm-6">
<label>Course Name *</label>
<input type="text" className="form-control" value={props.professionalLearnings.courseName || ''} onChange={ props.handleChange }
aria-describedby="Course Name" placeholder="Enter a course name" />
</div>
</div >
</form >
);
}

Input value not being re-rendered after calling this.setState({ term: ' ' }) in react

I am following a react tutorial and trying to re-render the value of a form input field after the user submits the form. However, the value in the input remains in a previous state despite updating the state as shown below.
constructor(props){
super(props);
this.state = { term: '' };
this.onInputChange = this.onInputChange.bind(this);
this.onFormSubmit = this.onFormSubmit.bind(this);
}
render(){
return(
<form onSubmit={this.onFormSubmit} className="input-group">
<input
placeholder="Search Days Forecast"
className="form-control"
value={this.state.value}
onChange={this.onInputChange}
/>
<span className="input-group-btn">
<button type="submit" className="btn btn-secondary"> Submit </button>
</span>
</form>
);
}
onInputChange(event){
this.setState({term: event.target.value});
}
onFormSubmit(event){
event.preventDefault();
this.props.fetchWeather(this.state.term);
this.setState({ term: '' });
}
}function mapDispatchToProps(dispatch){
return bindActionCreators({ fetchWeather }, dispatch);
}
export default connect(null, mapDispatchToProps)(SearchBar);
fetchWeather is just a function that sends a get request.
Any help on why the value field is not re-rendering with the new state will be highly appreciated.
try this
<input
placeholder="Search Days Forecast"
className="form-control"
value={this.state.term}
onChange={this.onInputChange}
/>

Categories