I have a form which is passed a value through props, and submits to an endpoint to update a users information. However, I'm unable to send an edited value of the text input field, as its state needs to be managed and updated when a user changes its value, but having trouble setting/updating the state of the input when the user changes the value, allowing a different value to be posted.
class DisplayNameModal extends React.Component {
constructor (props){
super(props)
this.state = {
displayName: this.props.displayName,
email: this.props.email.split('#')[0]
}
this.updateDisplayName = this.updateDisplayName.bind(this)
}
updateDisplayName () {
const email = this.props.email
const displayName = this.state.displayName
const user = {
email,
displayName
}
superagent
.put('/api/user')
.send({user})
.then(this.closeModal)
}
handleDisplayNameChange = e => this.setState({ displayName: e.target.value })
render (props) {
const {contentStrings} = this.props.config
return (
<div>
{ !this.props.displayNameModalActive &&
<div className='display-name-container' style={{ backgroundImage: `url(${this.props.bgImgUrl})` }}>
<div className='display-name-content'>
<h2 className='heading'>{contentStrings.displayNameModal.heading}</h2>
<p>{contentStrings.displayNameModal.subHeading}</p>
<input type="text"
defaultValue={this.state.displayName}
onChange={this.handleDisplayNameChange}
minLength="3"
maxLength="15"/>
<button
type='submit'
onClick={this.updateDisplayName}
className='btn btn--primary btn--md'>
<span>{contentStrings.displayNameModal.button}</span>
</button>
<p className='cancel'>{contentStrings.displayNameModal.cancel}</p>
</div>
</div>
}
</div>
)
}
}
export default DisplayNameModal
I think you need an onChange on your <input /> to update displayName on component state.
handleDisplayNameChange = e => this.setState({ displayName: e.target.value });
<input type="text"
value={this.state.displayName}
minLength="3"
maxLength="15"
onChange={this.handleDisplayNameChange}
/>
and instead of defaultValue, use value to make it a controlled input
So then in your updateDisplayName, you would use this.state.displayName instead of this.props.displayName. The prop is just being used to set the initial component state value, allowing it to be edited.
onChange event, call a method, and inside it use this.setState to set the changed text to state as you type in Input box.
On submit, use the updated State value to pass it to the API.
In this way, you can maintain updated value in local state.
You are using uncontrolled input element, ie React doesnt know, wats going on with ur input element.
In order, for React to know about it, it hould be made controlled component.
This can be done by connecting it value to the the state of the component,
Check example below.
This means, that at any time, react will know, wat is the value of the input element
Controlled Components
In HTML, form elements such as , , and typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with setState().
We can combine the two by making the React state be the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.
For example, if we want to make the previous example log the name when it is submitted, we can write the form as a controlled component:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Since the value attribute is set on our form element, the displayed value will always be this.state.value, making the React state the source of truth. Since handleChange runs on every keystroke to update the React state, the displayed value will update as the user types.
With a controlled component, every state mutation will have an associated handler function. This makes it straightforward to modify or validate user input. For example, if we wanted to enforce that names are written with all uppercase letters, we could write handleChange as:
handleChange(event) {
this.setState({value: event.target.value.toUpperCase()});
}
Related
I have a form on my React site and I am trying to get the data that a user enters. I have followed the documentation here, and a similar Stack Overflow post here, and when I press the submit button, I get the alert message. However, it doesn't let me type anything in the input field.
My code:
class Search extends Component {
constructor(props) {
super(props);
this.state = { value: "" };
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<div className="Search">
<form className="searchBox" onSubmit={this.handleSubmit}>
<input type="text" value={this.state.value}/>
<input type="submit" value="Go" />
</form>
</div>
);
}
}
If you are using default form setup of react then you need to use onChange handler for every input field and also maintain states for those fields too but in my opinion you should use Formik as it provides way more functionalities than default react form setup and also form validations.
But to give you an answer of your question -
Use onChange handler for your input field and during submission access those input handler states.
I have a React app using hooks and trying to figure out how to keep a submit button disabled if the search field is empty.
Assuming a regular form field with submit button, how can I set a state hook that keeps the search button disabled until the user inputs text. I assume there should be an onChange function that probably updates the state on input change, but not exactly sure of the implementation.
const [disabled, isDisabled] = useState(true);
<input type="text" id="q" name="q" placeholder="Search.." name="search">
<button type="submit"><i class="fa fa-search"></i></button>
If you want to disable a button when an input string is empty, then the only state you need is the value of the input string.
const [inputVal, setInputVal] = useState('')
// ...
<input value={inputVal} onChange={e => setInputVal(e.target.value)} />
// ...
<button disabled={!inputVal}> /* ... */ </button>
Here we connect the input component to the state value. This is called a controlled component, because its value is controlled from by an external source (the state value) as opposed to an uncontrolled component, which means the input element holds it's own internal state (the default way inputs work if you don't set their value prop directly.
When the input component receives input (such as someone typing a character) the onChange prop is called. All we do then is take the new value of the input element (e.target.value) and use it to set the state.
If you can derive state from other state, then you shouldn't be storing it in state. Having a state variable called disabled only makes things more complex. The general idea is to use as little state as possible, and compute as much as you can from that state.
Please check this complete example where I used class component and use a disable property under state object. When you write something on textbox, the disable property will be set as false.
import React from "react";
export default class Login extends React.Component {
constructor(props) {
super(props);
this.state = {disable: true};
}
handleChange = (event) => {
this.setState({disable: event.target.value === ''})
};
render() {
return (
<div>
<div>
Name: <input onChange={this.handleChange}/> <br/>
<button disabled={this.state.disable} >Login</button>
</div>
</div>
);
}
}
here is the same example of functional component
import React, {useState} from "react";
export default function Login() {
const [disable, setDisable] = useState(true);
function handleChange(event) {
setDisable(event.target.value === '');
}
return (
<div>
<div>
Name: <input onChange={handleChange}/> <br/>
<button disabled={disable}>Login</button>
</div>
</div>
);
}
I am new to react and while learning I come across this example of controlled component.
function App() {
let [fName, setFName]=useState('');
return (
<div className="container">
<h1>Hello {fName }</h1>
<input name ='fname' value={fName} onChange={(e)=> setFName(e.target.value)} type="text" placeholder="What's your first name?" />
</div>
);
}
just adding value={fName} makes is controlled . I don't actually understand what does it mean by controlled component and uncontrolled. Can you explain it from beginner prospective.
An uncontrolled component means that you will let the component itself manage the value. It's own internal mechanism will keep track of it.
Now when you add the value property to the input component, you will start to "control" the component yourself. The value you put into that property, will be the value that will be displayed.
You can literally control the value yourself, by just passing it in as is, or by changing the value before passing it in.
Controlled Components
These components have what is called a callback function that is triggered each time we enter something new in the form element.
Triggering the function will typically store or update what we type in the same React component that displays the form element that was used
Most widespread use it with forms
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Unontrolled Components
These components such as <input> typically maintain their own state and update it based on user input.
In other words, they will accept what we type and have the responsibility of remembering it, and in order to retrieve the values they remembered, you have to get it when you need it.
The latter usually happens during form submission. They can be classified under uncontrolled components.
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.input = React.createRef();
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Here, Reactjs documentation provided explanation.
A Controlled Component is one that takes its current value through props and notifies changes through callbacks like onChange. A parent component "controls" it by handling the callback and managing its own state and passing the new values as props to the controlled component. You could also call this a dumb component/stateless component.
An Uncontrolled Component is one that stores its own state internally, and you query the DOM using a ref to find its current value when you need it. This is a bit more like traditional HTML.
React form components support both controlled and uncontrolled usage:
// Uncontrolled:
<input type="text" defaultValue="hey" ref={inputRef} />
// Controlled:
<input type="text" value={this.state.value} onChange={onHandleChange} />
Trying to go from the search using the react datepicker and then check available dates. Having some trouble passing the props to the btn so I can create the new page based on the date selected.
Everything is Imported correctly we can leave that out below is my Datapicker Component and the Btnsearch Component I need the pops to be used by.
I have tried to pass the prop in every element on the component, with the btn built in to the component. I have read its better to pass the props down the chain of elements. To children so I tried to do that lastly. Still can't seem to catch the Datepicked to even console.log it.Tried to build a alert as well.
class Datepicker extends React.Component {
constructor(props) {
super(props);
this.state = {
value: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
alert("A name was submitted: " + this.state.value);
event.preventDefault();
}
state = {};
render() {
console.log(this.props.value);
return (
<>
<FormGroup>
<InputGroup className="input-group-alternative">
<InputGroupAddon addonType="prepend">
<InputGroupText
>
<i className="ni ni-calendar-grid-58" />
</InputGroupText>
</InputGroupAddon>
<ReactDatetime
value={this.state.value}
onChange={this.handleChange}
inputProps={{
placeholder: "Date Picker Here"
}}
timeFormat={false}
/>
</InputGroup>
</FormGroup>
<Btnsearch />
</>
);
}
}
export default Datepicker;
class Btnsearch extends React.Component {
render() {
return (
<button value={this.props.value} className="btn btn-success search-card-btn">Search</button>
);
}
};
export default Btnsearch;
I expect to console.log and alert the props been changed when the button is clicked in order to populate a new page. I get props undefined
Just pass down the prop:
<Btnsearch value={this.state.value}/>
Otherwise your component would never get it.
Edit: there was several issues in your code, I made a snippet for you to check.
https://stackblitz.com/edit/react-af37vl
Select a date, hit "search" and date will be logged in console.
Notice (from react-datetime docs):
Callback trigger when the date changes. The callback receives the
selected moment object as only parameter, if the date in the input is
valid. If the date in the input is not valid, the callback receives
the value of the input (a string).
I have a component in a React class in my Laravel project which is a simple form with one input field. It houses a phone number which I have retrieved from the database and passed back through the reducer and into the component as a prop. Using this, I have passed it through to the module as a prop which then populates the field with the currently saved value:
<OutOfOfficeContactNumberForm
show={props.showOutOfOffice}
value={props.outOfOfficeNumber}
handleChange={console.log("changed")}
/>
I have a handleChange on here which is supposed to fire a console log, but it only ever displays on page load. Here is my form module class:
class OutOfOfficeContactNumberForm extends React.Component {
render() {
const { show, value, handleChange } = this.props;
if(!show) return null;
return (
<div>
<p>
Please supply an Out of Office contact number to continue.
</p>
<InputGroup layout="inline">
<Label layout="inline" required={true}>Out of Office Contact Number</Label>
<Input onChange={handleChange} value={value} layout="inline" id="out-of-office-number" name="out_of_office_contact_number" />
</InputGroup>
</div>
);
}
}
export default (CSSModules(OutOfOfficeContactNumberForm, style));
The form is embedded in my parent component, as follows:
return (
<SectionCategoriesSettingsForm
isSubmitting={this.state.isSubmitting}
page={this.props.page}
show={this.props.show}
categories={this.props.categories}
submitSectionCategoriesSettings={this._submit.bind(this, 'add')}
updateSelectedCategories={this._updateSelectedCategories.bind(this)}
selectedCategoryIds={this.state.selectedCategoryIds}
storedUserCategories={this.props.selectedCategories}
outOfOfficeNumber={this.state.outOfOfficeNumber}
onUpdateContactNumber={this._updateContactNumber.bind(this)}
/>
);
In my componentWillReceiveProps() function, I set the state as follows:
if (nextProps.selectedCategories && nextProps.selectedCategories.length > 0) {
this.setState({
outOfOfficeNumber: nextProps.outOfOfficeNumber,
selectedCategoryIds: nextProps.selectedCategories.map(c => c.id)
});
}
I'm pretty sure the reason it's not changing is because it's pre-loaded from the state which doesn't change - but if I cannot edit the field how can I get it to register a change?
EDIT: Just to clarify there are also checkboxes in this form for the user to change their preferences, and the data retrieved for them is set the same way but I am able to check and uncheck those no problem
Changes:
1- onChange expect a function and you are assigning a value that's why, put the console statement inside a function and pass that function toOutOfOfficeContactNumberForm component , like this:
handleChange={() => console.log("changed")}
2- You are using controlled component (using the value property), so you need to update the value inside onChange function otherwise it will not allow you to change means input values will not be not reflect in ui.
Check example:
class App extends React.Component {
state = {
input1: '',
input2: '',
}
onChange = (e) => this.setState({ input2: e.target.value })
render() {
return(
<div>
Without updating value inside onChange
<input value={this.state.input1} onChange={console.log('value')} />
<br />
Updating value in onChange
<input value={this.state.input2} onChange={this.onChange} />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
<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='app' />
I think the best way is when you get data from database put it to state and pass the state to input and remember if you want to see input changes in typing, use a function to handle the change and that function should change state value.
class payloadcontainer extends Component {
constructor(props) {
super(props)
this.state = {
number:1
}
}
render() {
return (
<div>
<input value={this.state.number} onChange={(e)=>this.setState({number:e.target.value})}></input>
<button onClick={()=>this.props.buyCake(this.state.number)}><h3>buy {this.state.number} cake </h3></button>
</div>
)
}
}