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>
)
}
}
Related
I have a ReactJs function that displays a simple dialogue box, and is intended to update a value for the parent component. The function looks like this:
export function MyDialogue(props: IMyProps) {
var myValue = 0;
return (
<div style={style}>
<label>Enter a number here: </label>
<input type="text" value={myValue} />
<button onClick={() => props.updateFunc(myValue)}>Update</button>
</div>
);
}
I've tried several variations of this; for example, passing in props.myValue, and even changing the function to a class and passing this.state.myValue in. In all but this example, myValue remains as it was in the parent class, and in this version, always 0.
updateFunc simply calls setState on the parent class, and having traced through it, it never gets called with the changed value.
I've seen some documentation that says to essentially handle the onChange event - is this the only way to make this work, or is there a way to implement data binding in React?
Just bind back your input to the parent's state via props.value;
MyDialogue.js
export function MyDialogue(props: IMyProps) {
return (
<div style={style}>
...
<input type="text" value={props.value} />
...
</div>
);
}
Parent.js
....
render(){
const { dialogueValue } = this.state;
return <MyDialuge value={dialogueValue} updateFunc={this.handleUpdate} />
}
You are using uncontrolled input because You are not keeping value of input inside state.
Solution is
With uncontrolled:
export class MyDialogue extends React.Component<IMyProps, {}>{
constructor() {
super();
this.input = React.createRef();
}
return (
<div style={style}>
<label>Enter a number here: </label>
<input type="text" ref={this.input} />
<button onClick={() => props.updateFunc(this.input.current.value)}>Update</button>
</div>
);
}
With controlled:
Maintain myValue state in parent and pass it to child.
and on change on input event call a function of parent which change myValue using setState,
Maintain myValye state inside MyDialogue and onClick pass it to parent.
You need to change this component to a stateful component
then do a two-way binding for your textbox and have it talk to local state and then use that state value to update parent component.
export class MyDialogue extends React.Component<IMyProps, {}>{
constructor() {
super();
this.state = {
myValue: 0
}
}
onChangeHandler = (event:any) =>{
this.setState({myValue:event.target.value});
}
return (
<div style={style}>
<label>Enter a number here: </label>
<input type="text" value={this.state.myValue} onChange={this.onChangeHandler}/>
<button onClick={() => props.updateFunc(this.state.myValue)}>Update</button>
</div>
);
}
I'm currently using the TextField from office UI fabric and using the onChanged property to assign my prop in react the value being entered similar to their GitHub example.
However, the event handler is called for each element being entered. How can I make a call to the event handler(this._onChange) only when the user finishes entering the entire text (eg on focus dismiss, etc)?
I'm guessing that would be more efficient than logging an event with each letter being entered.
New to react. Appreciate your help!
This is more of an in-general way React uses the input onChange event. With React, you want to keep the value of your input in state somewhere, whether that is component state or a global store like Redux. Your state and UI should always be in sync. Because of this, the onChange event fires for every character that is entered/removed so that you can update that state to reflect the new value. Inputs written this way are called Controlled Components and you can read more about them and see some examples at https://reactjs.org/docs/forms.html.
That being said, you can detect when the user leaves the input with the onBlur event, though I would not recommend using that to update the state with the value as you'll see that a Controlled Component will act read-only when you don't update the state in the onChange event. You will have to use an Uncontrolled Component, typically setting the initial value with defaultValue instead of value and making things more difficult for yourself.
// CORRECT IMPLEMENTATION
class ControlledForm extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
name: 'example'
};
this.handleNameChange = this.handleNameChange.bind(this);
}
handleNameChange(e) {
this.setState({
name: e.target.value
});
}
render() {
return (
<div>
<h1>Controlled Form</h1>
<input type="text" value={this.state.name} onChange={this.handleNameChange} />
<p>{this.state.name}</p>
</div>
);
}
}
// INPUT DOES NOT WORK
class BuggyUncontrolledForm extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
name: 'example'
};
}
render() {
return (
<div>
<h1>Buggy Uncontrolled Form</h1>
<input type="text" value={this.state.name} />
<p>{this.state.name}</p>
</div>
);
}
}
// NOT RECOMMENDED
class UncontrolledForm extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
name: 'example'
};
this.handleNameChange = this.handleNameChange.bind(this);
}
handleNameChange(e) {
this.setState({
name: e.target.value
});
}
render() {
return (
<div>
<h1>Uncontrolled Form</h1>
<input type="text" defaultValue={this.state.name} onBlur={this.handleNameChange} />
<p>{this.state.name}</p>
</div>
);
}
}
ReactDOM.render(
<div>
<ControlledForm />
<BuggyUncontrolledForm />
<UncontrolledForm />
</div>
, 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>
You may consider using React's onBlur prop which will be invoked when the input loses focus. Here is an example Codepen which window.alert's the <TextField> component's current value when it loses focus: https://codepen.io/kevintcoughlin/pen/zmdaJa?editors=1010.
Here is the code:
const {
Fabric,
TextField
} = window.Fabric;
class Content extends React.Component {
public render() {
return (
<Fabric>
<TextField onBlur={this.onBlur} />
</Fabric>
);
}
private onBlur(ev: React.FocusEvent<HTMLInputElement>) {
window.alert(ev.target.value);
}
}
ReactDOM.render(
<Content />,
document.getElementById('content')
);
I hope you find that helpful.
References
https://reactjs.org/docs/events.html#focus-events
You can keep your state and UI in sync but use things like your own deferred validation error-check functions to check if the value is good/bad AND/or if you want to do something like logging based on the value only after a certain amount of time passes. Some examples from this page copied below for quick reference - you can do whatever you want in your "_getErrorMessage" function (https://github.com/OfficeDev/office-ui-fabric-react/blob/master/packages/office-ui-fabric-react/src/components/TextField/examples/TextField.ErrorMessage.Example.tsx):
<TextField
label="Deferred string-based validation"
placeholder="Validates after user stops typing for 2 seconds"
onGetErrorMessage={this._getErrorMessage}
deferredValidationTime={2000}
/>
<TextField
label="Validates only on focus and blur"
placeholder="Validates only on input focus and blur"
onGetErrorMessage={this._getErrorMessage}
validateOnFocusIn
validateOnFocusOut
/>
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()});
}
I have the following code where the issue is the amount1 which the textbox is created through state is unable to edit. When i edit this textbox the value 10 is not changing from the textbox. The other normal textbox works as usual. Anyone knows the issue?
constructor(props) {
super(props);
this.state = {
amount1:"10",
amount2:"20",
input:"",
}
}
componentDidMount(){
var options = <input type="text" name="amount1" value={this.state.amount1}>
this.setState({'input':options})
}
render() {
return(
<div>
{this.state.input}
<input type="text" name="amount2" value={this.state.amount2}>
</div>
)
}
You are missing the close tag of input and since you are passing value from the state the input becomes read-only. So try defaultValue instead of value to make it editable.
Both your inputs don't change their value since they are bound to the values in the state,
this is your code
What you need to do is add an event handler to your input tag that changes the value saved in the state.
handleAmountInput = (event) => { this.setState({ amount: event.target.value }) }
render() {
return( this.handleAmountInput(event)} value={this.state.amount}> )
}
And you should close your input tag <input />
I think if you changed your render to the following, along w/ the onChange binding event, you should get the appropriate values in state.
onChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
render() {
return (
<div>
<input
type="text"
name="amount1"
value={this.state.amount1}
onChange={this.onChange.bind(this)}
/>
<input
type="text"
name="amount2"
value={this.state.amount2}
onChange={this.onChange.bind(this)}
/>
</div>
);
}
As mentioned previously, you are creating readOnly, uncontrolled elements. This is a good article on controlled (react recommended) vs uncontrolled:
https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/
How to set focus to an input element when it enters the DOM?
Scenario
When a button is clicked the input element is displayed. How to set the focus to this element?
Code-Snippet
class Component extends React.Component{
constructor(props) {
super(props);
this.state = {
showInput: false
}
}
render() {
return (
<div>
<div onClick={() => {
this.setState({showInput: true});
ReactDOM.findDOMNode(this.refs.myInput).focus() // <- NOT WORKING
}}>
Show Input
</div>
{
(this.state.showInput) ? (
<input
type="text"
ref="myInput"
/>
) : ""
}
</div>
);
}
}
Calling ReactDOM.findDOMNode(this.refs.myInput).focus() after state change does not work. Also changing just the style or type property on state change does not work.
Assuming you only need one visible input on the page at a time to have autofocus Poh Zi How's suggestion of using the autofocus is probably the simplest.
<input type="text" autofocus/>
should do the trick, no JS needed!
In the componentDidMount and componentDidUpdate hooks do this:
ReactDOM.findDOMNode(this.refs.myInput).focus()
you should use ref
<input ref={(input) => { this.inputSearch = input; }} defaultValue="search ... " />
and use this code for focus
this.inputSearch.focus();
I had to define the variable as HTMLInputElement 1st...
private inputSearch: HTMLInputElement;
And then add this into the control:
ref={(input) => { this.inputSearch = input; }}
THEN I could get this to build/work:
this.inputSearch.focus();
From the docs:
"findDOMNode only works on mounted components (that is, components that have been placed in the DOM). If you try to call this on a component that has not been mounted yet (like calling findDOMNode() in render() on a component that has yet to be created) an exception will be thrown."
As mentioned by Piyush.kapoor, you need to place that incomponentDidMount and/or componentDidUpdate.