can I update input field value with setState in react - javascript

I'm new to React and I implemented a form which uses Material-UI and react-input-mask library. I would like to know how to change user input value in the input field.
For example, I have this field:
class TemplateForm extends React.Component {
constructor(props) {
super(props);
this.state= {
api_access: true,
currency: "",
sku: "",
}
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChange = (event) => {
const {name, value} = event.target
this.setState({
[name]: value
})
}
onSubmit = (formVals) => {
return false;
}
renderField=({input,label, meta:{touched,error}})=> (
<InputMask mask="99/9999"
value = {this.state.edate}
name="edate"
type="tel"
required
{...input}
>
{(inputProps) =>
<TextField
{...inputProps}
label={label}
fullWidth
/>}
</InputMask>
)
handleBlur = (value) => {
valueM = value.split("/")
if (valueM[0].length< 2) {
valueM[0]= "0"+valueM[0]
}
valueM = valueM.join("/")
this.setState({
ename:valueM
})
}
<Field id="ename" name="ename" onBlur={this.handleBlur} component={this.renderField} />
}
I would like to change value of the month field with a leading zero when user enters only one digit. Like if user enters 1_/2022 should be converted to 01/2022 but this.setState() isn't changing the value in the field. How to achieve this?

Related

How to save input fields changes in React?

I created an update page in my react app.
To sum up; when I click a div it shows the data in input fields. For example, when I click the first field, type in there something, and click another div, the changes I made disappear. I want that if I make a change in there, It should stay there before save it. How can I do that?
<div className="detailsPage-panel-right">
{
this.state.activeFields?.fields?.map(field => {
const config = this.config.fields.find(fieldConfig =>
fieldConfig.key === field.key)
const inputConfig = {
type: config?.dataType.type,
id: config?.key,
label: config?.displayName,
required: false,
autofocus: false,
value: field.value
};
const inputBindings: ITextInputBindings = {}
return (
<div key={`${this.state.activeFields.key}-${field.key}`}>
<TextInput config={inputConfig} bindings={inputBindings}></TextInput>
</div>
)
})
}
</div>
Text input component
import "./text-field.scss";
import { Form } from "react-bootstrap";
import { Component } from "../../utils/stateless-component";
export interface ITextInputBindings {
}
export interface ITextInputConfig {
type: "text" | "dateTime" | "enumeration" | "guid" | undefined,
id: string | undefined,
label: string | undefined,
placeholder?: string,
required: boolean,
autofocus?: boolean,
value?: string
}
class TextInput extends Component<ITextInputConfig,ITextInputBindings> {
render() {
return (
<div className="textInput">
<Form.Group className="mb-3 textInput-group">
<Form.Label htmlFor={this.config.id}>{this.config.label}</Form.Label>
<Form.Control type={this.config.type}
placeholder={this.config.placeholder}
required={this.config.required}
id={this.config.id}
autoFocus={this.config.autofocus}
defaultValue={this.config.value} />
</Form.Group>
</div>
);
}
}
export default TextInput;
I think I should use onChange method but I don't know how.
key prop
Remember to check re-render when your activeFields.field changes, because you had set the key in your TextInput.
This will result in the TextInput component be unmount and create a new one
// 📌 check this state. Do not mutate to prevent re-render
this.state.activeFields?.fields?.map(field => {
const config = this.config.fields.find(fieldConfig =>
fieldConfig.key === field.key)
const inputConfig = {
type: config?.dataType.type,
id: config?.key,
label: config?.displayName,
required: false,
autofocus: false,
value: field.value
};
const inputBindings: ITextInputBindings = {}
return (
// 📌 if key be mutated from state, it will create a new component intead of old one
<div key={`${this.state.activeFields.key}-${field.key}`}>
<TextInput config={inputConfig} bindings={inputBindings}></TextInput>
</div>
)
})
Save Input value
And if you want to save the input value in TextInput, it is depends on which component you want to save the input value by state.
Save in the child component (In your case the TextInput)
Add a onChange event and a state in your TextInput component
Then add props because you are give props to it.
like this example edited from your code (maybe can not run, but the concept should work)
class TextInput extends Component<ITextInputConfig,ITextInputBindings> {
constructor(props) {
super(props);
this.state = { ...this.props }
}
// set state
const handleChange = (e) => {
this.setState({...this.state,
config: { ...this.state.config, value: e.target.value }
})
}
render() {
return (
<div className="textInput">
<Form.Group className="mb-3 textInput-group">
<Form.Label htmlFor={this.config.id}>{this.config.label}</Form.Label>
<Form.Control type={this.config.type}
placeholder={this.config.placeholder}
required={this.config.required}
id={this.config.id}
autoFocus={this.config.autofocus}
defaultValue={this.config.value}
// 📌 add onChange event on Form.Control
onChange={handleChange}
/>
</Form.Group>
</div>
);
}
}
Save in parent component
And if you need control or save state changes from parent component
add a state and a changeState function in your parent component, and give changeState to TextInput's props and let the
changeState prop mutate parent's value in child's input onChange event
example:
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = { inputValue: undefined }
}
const handleChange = (e) =>{
if(e.target)
this.setState({...this.state, inputValue: e.target.value});
}
render(){
return (
<div className="detailsPage-panel-right">
{
this.state.activeFields?.fields?.map(field => {
const config =
this.config.fields.find(fieldConfig =>
fieldConfig.key === field.key)
const inputConfig = {
type: config?.dataType.type,
id: config?.key,
label: config?.displayName,
required: false,
autofocus: false,
value: field.value
};
const inputBindings: ITextInputBindings = {}
return (
<div key=
{`${this.state.activeFields.key}-${field.key}`}
>
<TextInput
config={inputConfig}
bindings={inputBindings}
onChange={handleChange}>
</TextInput>
</div>
)
})
}
</div>
)
}
}
// TextInput
class TextInput extends Component<ITextInputConfig,ITextInputBindings> {
constructor(props) {
super(props);
this.state = { ...this.props }
}
const handleChange = (e) => {
this.props.onChange(e);
}
render() {
return (
<div className="textInput">
<Form.Group className="mb-3 textInput-group">
<Form.Label htmlFor={this.config.id}>{this.config.label} </Form.Label>
<Form.Control
type={this.config.type}
placeholder={this.config.placeholder}
required={this.config.required}
id={this.config.id}
autoFocus={this.config.autofocus}
defaultValue={this.config.value}
onChange={handleChange}/>
</Form.Group>
</div>
);
}
}
Code snippet example
a example that how child mutate parent's value, and how does the component destroyed when key changes. (written by functional component)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
function App () {
const [keys, setKeys] = React.useState([1, 2]);
const [inputValue, setInputValue] = React.useState(``);
const [inputValue2, setInputValue2] = React.useState(``);
const handleKeys = () =>{
let temp = [...keys];
temp[0] = temp[0] + 2;
temp[1] = temp[1] + 2;
setKeys([...temp])
}
return <div>
<div><button>Click this still remain the changes you had made</button></div>
<div><button onClick={handleKeys}>Click this to change keys, and will refresh the 'Number' prefix input component</button></div>
<br />
{
keys.map((key)=>{
if (key % 2 === 0) {
return <div key={key}>Number {key}: <Child setInputValue={setInputValue2}></Child></div>
}
else {
return <div key={key}>Number {key}: <Child setInputValue={setInputValue}></Child></div>
}
})
}
<br />
<div>child components that do not have key</div>
<div>First Child's Input: <Child setInputValue={setInputValue}></Child></div>
<div>Second Child's Input: <Child setInputValue={setInputValue2}></Child></div>
<br />
<div>inputValue(in parent from first child): {inputValue}</div>
<div>inputValue2(in parent from second child): {inputValue2}</div>
</div>
}
function Child ({ setInputValue }) {
const handleChange = (e) => {
if(setInputValue)
setInputValue(e.target.value);
}
return <input onChange={handleChange}></input>
}
</script>
<script type="text/babel">
ReactDOM.render(
<App></App>
, document.getElementById("root"));
</script>
Dynamically mutate and save input value by state
I guess you need save value dynamically by this.state.activeFields?.fields.
Create a state object for recording your active input value.
And add a handleChange function which can change value by e.target.id
// In your TextInput's parent
constructor(props) {
super(props);
this.state = { inputValues: {} }
}
const handleChange = (e)=>{
const changeField = this.state.activeFields?.fields.find(x=>x.key === e.target.key);
if(changeField) {
this.setState({...this.state.inputValues, changeField.key: e.target.value})
}
}
this.state.activeFields?.fields?.map( (field) => {
return (
<TextInput
config={inputConfig}
bindings={inputBindings}
// add onChange event
onChange={handleChange}
>
</TextInput>
)
})
more refernece:
Lifting State Up
Other
According to react-bootstrap's Form.Control API doc, should use the value intead of defaultValue

React on Rails: Can't enter text in my form input boxes

When I try to type in the boxes on the webpage it doesn't register that I am typing anything. I am guessing it has something to do with the handleChange or onChange, but I could use some help here. I am still pretty new to React and trying to figure it out. What am I missing here?
import React, {Component} from 'react';
import { Form } from 'semantic-ui-react';
class Assessments extends Component {
state = {assessment_name: '', assessment_type: ''}
componentDidMount() {
if (this.props.id) {
const { assessment_name, assessment_type } = this.props
this.setState({ assessment_name, assessment_type })
}
}
handleChange = (a) => {
const { name, value } = a.target
this.setState({ [name]: value })
}
handleSubmit = (a) => {
a.preventDefault()
if (this.props.id) {
const { id, history } = this.props
this.props.updateName(id, this.state, history)
this.props.toggleUpdate()
}
this.props.close()
this.setState({ assessment_name: '', assessment_type: ''})
}
close = () => this.setState({ open: false })
render() {
const { assessment_name, assessment_type } = this.state
return(
<Form onSubmit={this.handleSubmit}>
<Form.Input
name=''
value={assessment_name}
onChange={this.handleChange}
label='Assessment Name'
required
/>
<Form.Input
name='AssessmentType'
value={assessment_type}
onChange={this.handleChange}
label='Assessment Type'
required
/>
<Form.Button>Submit</Form.Button>
</Form>
)
}
}
export default Assessments;
You're not passing the right names to the Form.Input components which the handleChange function uses to update the state. They have to be 'assessment_name' and 'assessment_type' respectively to make sure the state gets updated on input change events and the new values get reflected on the fields.
<>
<Form.Input
name="assessment_name"
value={assessment_name}
onChange={this.handleChange}
label="Assessment Name"
required
/>
<Form.Input
name="assessment_type"
value={assessment_type}
onChange={this.handleChange}
label="Assessment Type"
required
/>
</>

Input-Component: React does not recognize the prop on a DOM Element

I am facing an issue when I try to set the state of a component in the Input field. I have tried by setting the Object values in the constructor but that didn't work either. If I remove the prop the input field is not getting any value. I have posted my JS code below.
Input Component:
<div className="form__group">
<input
className="form__field"
id={props.name}
name={props.name}
type={props.inputtype}
value={props.value}
onChange={props.handleChange}
placeholder={props.placeholder}
{...props}
/>
<label htmlFor={props.name} className="form__label">{props.placeholder}</label>
</div>
JSX Code:
<Input
inputtype={"text"}
title={"Full Name : "}
name={"name"}
value={this.state.newUser.name}
handleChange={this.handleInput}
placeholder={"Enter your Name"}
/>{" "}
JS Code:
class FormContainer extends Component {
constructor(props) {
super(props);
this.state = {
newUser: {
name: "",
age: "",
gender: "",
skills: [],
about: ""
},
this.handleInput = this.handleInput.bind(this);
}
handleInput(e) {
let value = e.target.value;
let name = e.target.name;
this.setState(
prevState => ({
newUser: {
...prevState.newUser,
[name]: value
}
}),
() => console.log(this.state.newUser)
);
}
}
handleChange is passed on because of {...props}, and is not a valid for the input element.
If you spread out the props in the parameters:
const Input = ({ name, inputType, value, handleChange, placeholder, ...props}) => {
and then
<input
className="form__field"
id={name}
name={name}
type={inputType}
value={value}
onChange={handleChange}
placeholder={placeholder}
{...props}
/>
Actually there is a problem in your JSX (handleChange instead of onChange, but it is not the main thing)
So in my example your final code should look like this
handleInput = (input) => {
this.setState({ newUser: { [input.target.name]: input.target.value } });
}
<Input
inputtype="text"
title="Full Name : "
name="name"
value={this.state.newUser.name}
onChange={this.handleInput}
placeholder="Enter your Name"
/>

React refactor simple input component

I have multiples components who needs input value
so I copy/paste my following code on the render method :
<input type="password"
name="password" value={user.password}
placeholder="password"
onChange={e => this.handleChange(e)}/>
And I copy/paste the handleChange method in all my component :
handleChange(event) {
const {name, value} = event.target
this.setState({
[name]: value,
})
}
I would like to have input in a component and call it from all my components and then get input value to add it to my current state component
Do you have any solution ?
Thanks
If I understand correctly you wan't something like this:
class MyWrapperComponent extends React.Component {
constructor(props) {
this.state = { password: '' }
}
handleChange(event) {
const {name, value} = event.target
this.setState({
[name]: value,
})
}
render() {
return (
<div>
<MyInputComponent value={this.state.password} onChange={this.handeChange.bind(this)} />
<MyDisplayPasswordComponent password={this.state.password} />
</div>
)
}
}
const MyInputComponent = (props) => {
return (
<input type="password"
name="password" value={props.password}
placeholder="password"
onChange={props.onChange}/>
)
}
const MyDisplayPasswordComponent = (props) => {
return <h1>Your secret password is {props.password}</h1>
}

enable button to submit only when all the fields are filled

I have a form which has 3 field. First two fields are email_from and email_subject and the last field is an editor. I have used draftjs for editor. If there is no editor i could enable and disable the submit button but due to the inclusion of the editor i did not know how can i enable the button only when all the fields are filled with no error.
Here is my code.
AdminEditor is the component which has draftjs editor
class EmailTemplate extends React.Component {
state = {
emailSubject: '',
emailFrom: ''
};
handleChange = event =>
this.setState({ [event.target.name]: event.target.value });
handleSubmit = event => {
event.preventDefault();
};
render() {
const { emailSubject, emailFrom } = this.state;
return (
<form onSubmit={this.handleSubmit}>
<FieldGroup
id="formControlsText"
name="emailSubject"
type="text"
label="Email Subject"
placeholder="Enter Email Form"
onChange={this.handleChange}
validationState={emailSubject ? 'success' : 'error'}
required
/>
<FieldGroup
id="formControlsText"
name="emailFrom"
type="email"
label="Email From"
placeholder="Enter Email From"
onChange={this.handleChange}
validationState={emailFrom ? 'success' : 'error'}
required
/>
<AdminEditor />
<Button type="submit">
Submit
</Button>
</form>
);
}
}
export default EmailTemplate;
class AdminEditor extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
isEmpty: true
};
}
onEditorStateChange = editorState => {
this.setState({
editorState
});
};
onEditorChange = editorContent => {
this.setState({
editorContent
});
};
handleChange = event =>
this.state.editorState.getCurrentContent().hasText()
? this.setState({ isEmpty: false })
: this.setState({ isEmpty: true });
render() {
const { editorState } = this.state;
return (
<div>
<Editor
editorState={this.state.editorState}
initialContentState={rawContentState}
toolbarClassName="home-toolbar"
wrapperClassName="home-wrapper"
editorClassName="home-editor"
onEditorStateChange={this.onEditorStateChange}
toolbar={{
textAlign: { inDropdown: true },
}}
onContentStateChange={this.onEditorChange}
placeholder="write text here..."
onChange={this.handleChange}
/>
</div>
);
}
}
export default AdminEditor;
Can anyone please help me?
There are many ways to do this, mostly based around passing some callbacks down into the controlled component which updates the state in the parent.
A simple way would be to pass a handler that sets a flag if the editor is empty or not:
class AdminEditor extends React.PureComponent {
...
handleChange = event =>
this.props.setEditorIsEmpty(
this.state.editorState.getCurrentContent().hasText()
);
Then in EmailTemplate:
setEditorIsEmpty(editorIsEmpty) {
this.setState({
editorIsEmpty
});
}
render() {
const { emailSubject, emailFrom } = this.state;
return (
<form onSubmit={this.handleSubmit}>
...
<AdminEditor
setEditorIsEmpty={this.setEditorIsEmpty}
/>
<Button
type="submit"
disabled={!emailSubject || !emailFrom || editorIsEmpty}>
Submit
</Button>
</form>
);
}

Categories

Resources