Mobile number masking in React - javascript

Hi need to masked mobile number when user enter the mobile number in input box it should be 021 121 4544 in this format.
means there should be 021{auto space}121{auto space}4544
how can i build in react this functionality?
class NumberCheck extends Component {
state = {
disabled: true,
errorBlock: 'none',
mobileNumber: '',
error: ''
};
handleOnChange = (event) => {
let disabled = event.target.value ? disabled = false : disabled = true;
this.setState({
disabled: disabled,
mobileNumber: event.target.value
})
}
submit = (e) => {
e.preventDefault();
if (this.state.mobileNumber.match(/^02[0-9]{6,11}$/)) {
this.setState({
errorBlock: 'none'
})
const payload = {
msisdn: this.state.mobileNumber
}
this.props.checkNumber(payload);
} else {
this.setState({
error: ' Please enter valid mobile no',
errorBlock: 'block'
})
}
}
render() {
const { isLoading, isError } = this.props;
if (isLoading) {
return <Spinner />
}
if (isError) {
return <ChangePlanError />
}
return (
<form className="spring spring--sm">
<p className="heading heading--3 heading--center no-gutter--top">{"Already with Vodafone?"}</p>
<p className="heading--center">{"Sign in using a TXT code to check if you are eligible to upgrade or change your plan"}</p>
<div className="alert alert--light alert--warning alert--arrow validation__warning" style={{ display: this.state.errorBlock }}>
<div className="caption">
< div className="caption__media caption__media--top alert__media" >
<svg className="icon icon--extra-small icon--inherited" data-vft="icon-modifiers">
<use xmlnsXlink="http://www.w3.org/1999/xlink" xlinkHref="#icon-block" />
</svg>
</div>
<div className="caption__text caption__text--top alert__text">
{this.state.error}
</div>
</div>
</div>
<input
type="text"
onChange={this.handleOnChange}
className="form__input form__input--dark"
name="mobileno"
placeholder="021 1234567"
mask="000 000 0000" />
<div id="submit" className="form__row form__row--medium gutter--bottom">
<input
type="submit"
className={`button button--primary button--primary--grey button--full-width ${this.state.disabled ? 'button--disabled' : ''}`}
value=" Continue"
onClick={this.submit} />
</div>
</form >
);
}
}

You can create a new string with previous string and replace it in the input.
const number = '0211214544';
const num = `${number.substring(0, 3)} ${number.substring(3, 6)} ${number.substring(6, number.length)}`;
console.log(num);
Created a working example in React.
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
name: ''
};
}
change = (event) => {
let val = event.target.value;
val = val.replace(/ /gm, '');
console.log(val);
let num = `${val.substring(0, 3)} ${val.substring(3, 6)} ${val.substring(6, val.length)}`;
num = num.trim();
this.setState({
name: num
});
};
render() {
return (
<div className="App">
<input
ref="inputName"
value={this.state.name}
onChange={this.change}
/>
</div>
);
}
}
export default App;

The below function will mask the phone number , the basic operation to perform such functions is slicing/sub string and string concatenation
maskingFunction= (phoneNumber)=>{
let subNum = phoneNumber.toString().substring(0,3)
subNum = subNum + "XXXXXXXXXXXX"
return subNum
}

I created a package that exposes an input component that displays a masked value according to the mask it receives.
The mask will change keeping the cursor at the correct position (even if you change part of the value in the middle of the input, paste some characters, or delete a part of it, and even if the mask changes).
You can see a Demo with examples at:
https://lucasbasquerotto.github.io/react-masked-input
(The first example has an input with the mask asked in this SO question: 999 999 9999).
To install the package: npm i react-hook-mask
Use it:
import { MaskedInput, createDefaultMaskGenerator } from 'react-hook-mask';
const maskGenerator = createDefaultMaskGenerator('999 999 9999');
const MobileNumberMaskedInput = () => {
const [value, setValue] = React.useState('');
return (
<MaskedInput
maskGenerator={maskGenerator}
value={value}
onChange={setValue}
/>
);
};
This component wraps a default input, but the package also expose hooks to make you able to use it with any kind of component.
The function createDefaultMaskGenerator that always return a static string mask. You can also use dynamic masks that change according to the value, and even transforming the value (for example, making the characters uppercase).
The hook useMask is a generic hook that can be used with any component (even native components) as long as the component has a way to retrieve and to modify the cursor position.
The hook useRefMask wraps useMask and provides an easy way to forward a ref to the component, as well as using the ref element in the functions that manage the cursor position (Example).
The (more specific) hook useWebMask wraps useRefMask and can be used with any custom react-dom component that wraps an input and whose ref is an HTMLInputElement, without having to define a getter and a setter for the cursor position, and with an onChange function that sets the value received from the event object (Example).

Related

Why I cant share info between form input (child component) and React useState Hook (parent component)?

I am doing a multiple step form with React and I expect that when the user hits "Next" button, he/she can go to the next form, save info in parent component useState Hook and keep it in the input if user decides to go back. Switch has 8 cases but I left only 1 for simplicity. Structure looks something like this (Questions after code):
<MainForm />
|_ <UserInfo />
|_ Another 7 childs
MainForm.js
import React, { useState } from "react";
import UserInfo from "../components/Shared/UserInfo";
//import ... more childs ...
import {
BackButton,
NextButton,
SendButton,
} from "../components/Shared/Buttons";
const BDMForm = (props) => {
const [step, setStep] = useState(1);
const [datos, setDatos] = useState({
fullName: "",
email: "",
phoneNumber: "",
linkedIn: "",
city: "",
experience: "",
});
const handleChange = (e) => {
setDatos({ ...datos, [e.target.name]: e.target.value });
};
function renderComponent(step) {
let currentStep = step;
switch (currentStep) {
case 1:
return <UserInfo handleChange={handleChange} datos={datos.fullName} />;
// 7 more cases
}
return (
<form>
{renderComponent(step)}
<div className="button-container">
<BackButton step={step} setStep={setStep} />
{step >= 7 ? null : <NextButton step={step} setStep={setStep} />}
{step === 7 ? <SendButton /> : null}
</div>
</form>
);
};
export default MainForm;
UserInfo.js
import React from "react";
return (
<div className="card-container">
<label>
Nombre y Apellido<span> *</span>
</label>
<input
type="text"
name="fullName"
value={props.datos}
onChange={props.handleChange}
/>
</div>
</div>
);
};
export default UserInfo;
I have 2 questions:
1) When I write something on fullName input (UserInfo.js), I think React is updating the component with the default value ("") so I cant write anything on it.
Expected behavior:
User can write and input should be saved in datos.fullName on parent component.
When user press Next or back, written information will still be there.
2) Is my approach OK? Should I be saving all children data in parent component and then access it from another child later on (Like Confirm.js or somewhere where the user can read the information before send it). I tried to learn Context API but still don't understand how to implement it πŸ˜…
Change your handleChange function like this:
const handleChange = (e) => {
const fieldName = e.target.name;
const fieldValue = e.target.value;
setDatos(prevDatos => ({ ...prevDatos, [fieldName]: fieldValue }));
};
When the new state depends on the previous state you have to use the functional way to update the state.
Regarding your second question, yes, your approach is fine.
And finally, I would maintain some consistency when defining the functions. I'm referring to handleChange and renderComponent functions.

I'm having trouble changing the value in input

Part of the project is as follows:
...
const INITIAL_STATE = {
email: '',
password: '',
error: null
}
const SignInPage = () => {
return(
<div>
<h2>Sign In</h2>
<SignInForm/>
<SignUpLink/>
</div>
)
}
const SignInFormBase = props => {
const[init,setInit] = useState(INITIAL_STATE);
const onSubmit = () => {
}
const onChange = (event) => {
setInit({
[event.target.name]: event.target.value
})
}
const isInvalid = init.password === '' || init.email === '';
return(
<form onSubmit={onSubmit}>
<input
name='email'
value={init.email}
onChange={onChange}
type='text'
placeholder='Email Address'
/>
<input
...
/>
<button disabled={isInvalid} type='submit'>Sign In</button>
{init.error && <p>{init.error.message}</p>}
</form>
)
}
const SignInForm = compose(
withRouter,
withFirebase
)(SignInFormBase)
export default SignInPage;
export {SignInForm}
The problem is:
When I replace the values ​​in init with setInit in the onChange function, I get the following error.
Warning: A component is changing a controlled input of type text to be uncontrolled. Input elements should not switch from controlled to uncontrolled (or vice versa) . Decide between using a controlled or uncontrolled input element for the lifetime of the component.
Note: I have the same problem in the password section
You strip part of the code but I assume that you didn't read react hooks documentation good enough. By using hooks you won't get replacement for the setState which was previously merging the values. Therefore when you call
setInit({
[event.target.name]: event.target.value
})
you will replace whole init variable with the new object therefore other field will be pointing to undefined value and react will change component to uncontrolled, then again to controlled when you enter value. If you want to maintain object in state you need to do merging by yourself. Easiest way would be to use object spread as
setInit({
...init, // <- spread old state
[event.target.name]: event.target.value
})
With this code old state will remain between inputs. I would also suggest you to not infer state property from the field name as later you can easily introduce bug you can create curried global onChange as
const onChange = (field) => (event) => {
setInit({
...init,
[field]: event.target.value
})
}
return (
<input onChange={onChange('name')} />
)

How to get initial and setState value of contentEditable Input in ReactJS?

I am trying to build a comment box using contentEditable div and have
the following issues:
Not able to get the initial value of the text property.
Not getting the setState value from contentEditable.
Having issues with emoji's which are working fine when using the input element but does not work with contentEditable.
With the code provided below, I am getting undefined when console.log,
not sure what I am missing.
Expected Outcome.
get the typed value from contentEditable including the emoji's.
// Content Input Model
import React, { Fragment } from 'react'
import '../../assets/css/comment.css'
const ContentInput = ({valueChange,contentInputId,ref,onClick,onPhClick,placeholder, ...props }) => {
return (
<Fragment>
<div
spellCheck="false"
role="textbox"
id={contentInputId}
ref={ref}
contentEditable="true"
onChange={valueChange}
aria-multiline="true"
data-placeholder={placeholder}
{...props}
/>
<div className="comment_submit_button" onClick={onClick}>
<span className='submit_arrow_light'> </span>
</div>
</Fragment>
)
};
export default ContentInput
// Comment Modal///
import React , {Component} from 'react';
import EmojiPicker from 'emoji-picker-react'
import '../../../../assets/css/comment.css'
import JSEMOJI from 'emoji-js'
import ContentInput from "../../../../UIElements/Inputs/ContentInput";
//emoji set up
let jsemoji = new JSEMOJI();
// set the style to emojione (default - apple)
jsemoji.img_set = 'emojione';
// set the storage location for all emojis
jsemoji.img_sets.emojione.path = 'https://cdn.jsdelivr.net/emojione/assets/3.0/png/32/';
class CommentModal extends Component {
constructor(props) {
super(props);
this.state = {
text : ' ' ,
emojiShown : false ,
};
this.desChange = this.desChange.bind(this);
}
desChange = (e) => {
// let text = this.state.text;
this.setState({text : e.target.value});
};
comment = (e) => {
e.preventDefault();
let {text} = this.state;
let {back , incrementComments , ...rest} = this.props;
const updatedText = this.setState({text : e.target.value});
console.log(updatedText);
};
//displays emoji inside the input window
handleEmojiClick = (n , e) => {
let emoji = jsemoji.replace_colons(`:${e.name}:`);
this.setState({
text : e.target.value + emoji ,
emojiShown : !this.state.emojiShown
});
console.log(this.emojiShown)
};
toggleEmojiState = () => {
this.setState({
emojiShown : !this.state.emojiShown
});
};
render() {
return (
<div className='comment_model_container display_none'>
<div className="comment_content_container global_bt">
<div className="comment_text_area_container ">
<ContentInput
valueChange={this.desChange}
contentInputId='comment_box'
onClick={this.comment}
spellcheck="true"
className='comment_text_area global_bt'
placeholder='Leave a comment...'
/>
</div>
<div>
</div>
<div className='emoji_container'>
<span id="show-emoji-yes" onClick={!this.toggleEmojiState}><span
className='grey_smiley_icon'> </span></span>
<div className="emoji-table">
<EmojiPicker onEmojiClick={this.handleEmojiClick} className='emoji_popup'/>
</div>
</div>
</div>
</div>
);
}
}
export default CommentModal;
```
Use onInput on ContentInput instead of onChange
And use e.target.innerHTML on desChange instead of e.target.value
contentEditable event should be 'onInput'
Content Editable change events

Typing in react form input causes focus loss and re-render

I have the following code, which results in the focus being lost as soon a key is pressed in the firm password field. Exploration suggests the form is being re-rendered, as a result of setState but I am not sure why or how to fix.
import React from 'react';
import LocalizedStrings from 'react-localization';
let strings = new LocalizedStrings({
// code omitted
});
class ResetPasswordForm extends React.Component {
constructor (props) {
super(props);
this.state = {
key: this.props.key,
password: '',
passwordConfirm: ''
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
handleSubmit(event) {
event.preventDefault();
// TODO
}
renderField(field) {
const name = field.name;
const id = field.id || name;
const label = strings[name];
const fieldType = field.type || 'text';
const placeholder = strings[name + '-placeholder'];
// TODO
let touched;
let error;
return <div className="form-group">
<label htmlFor={id}>{label}:</label>
<input id={id} type={fieldType} placeholder={placeholder} name={name} onChange={this.handleChange}
value={this.state[name]}
className="form-control"/> {touched && error && <div className="error bg-warning">{error}</div>}
</div>
}
render() {
const Field = this.renderField.bind(this);
return (
<div>
<h2>{strings['title']}</h2>
<form onSubmit={this.handleSubmit} >
{this.props.statusText && <div className='alert alert-info'>
{this.props.statusText}
</div>}
<Field
name="password"
type="password"
/>
<Field
name="passwordConfirm"
type="password"/>
<div className="form-group">
<input
type="submit"
name="Submit"
defaultValue={strings['submit']}
/>
</div>
</form>
</div>
)
}
}
Edit: Further experimenting suggest that 'Field' lines are causing the issue and replacing them with the following resolves the issue:
{this.renderField({
name: "password",
type: "password"
})}
{this.renderField({
name: "passwordConfirm",
type: "password"
})}
Alternatively, in the constructor I can do:
this.renderField = this.renderField.bind(this);
and then in the render function I can do:
const Field = this.renderField;
While these approaches work, I am not sure the exact impact of the change sin terms of React. If anyone can explain, it would be appreciated.
I think here is the error:
const Field = this.renderField.bind(this);
renderField(field) accept the object parameter(field) and you never pass it. So you need to pass it
const Field = this.renderField.bind(this, { name: "password", type: "password"});
Each time render is executed, you generate new function-Component with this.renderField.bind(this). In this case, React's reconciliation algorithm will treat this as a difference, and the entire subtree will be rendered from scratch.
From docs:
Elements Of Different Types
Whenever the root elements have different types, React will tear down
the old tree and build the new tree from scratch. Going from to
, or from to , or from to - any
of those will lead to a full rebuild.
Here is a screencap of DevTools elements inspector, which illustrates DOM updates in both cases
Original (Field is generated on each render)
You can see that the <div> node is collapsed and rendered from scratch => focus is lost.
Fixed (this.renderField({...}) is used)
Only "value" field is updated, the rest of DOM is intact => focus is preserved

React - changing an uncontrolled input

I have a simple react component with the form which I believe to have one controlled input:
import React from 'react';
export default class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={this.state.name} onChange={this.onFieldChange('name').bind(this)}/>
</form>
)
}
onFieldChange(fieldName) {
return function (event) {
this.setState({[fieldName]: event.target.value});
}
}
}
export default MyForm;
When I run my application I get the following warning:
Warning: MyForm is changing an uncontrolled input of type text to be
controlled. Input elements should not switch from uncontrolled to
controlled (or vice versa). Decide between using a controlled or
uncontrolled input element for the lifetime of the component
I believe my input is controlled since it has a value. I am wondering what am I doing wrong?
I am using React 15.1.0
I believe my input is controlled since it has a value.
For an input to be controlled, its value must correspond to that of a state variable.
That condition is not initially met in your example because this.state.name is not initially set. Therefore, the input is initially uncontrolled. Once the onChange handler is triggered for the first time, this.state.name gets set. At that point, the above condition is satisfied and the input is considered to be controlled. This transition from uncontrolled to controlled produces the error seen above.
By initializing this.state.name in the constructor:
e.g.
this.state = { name: '' };
the input will be controlled from the start, fixing the issue. See React Controlled Components for more examples.
Unrelated to this error, you should only have one default export. Your code above has two.
When you first render your component, this.state.name isn't set, so it evaluates to undefined or null, and you end up passing value={undefined} or value={null}to your input.
When ReactDOM checks to see if a field is controlled, it checks to see if value != null (note that it's !=, not !==), and since undefined == null in JavaScript, it decides that it's uncontrolled.
So, when onFieldChange() is called, this.state.name is set to a string value, your input goes from being uncontrolled to being controlled.
If you do this.state = {name: ''} in your constructor, because '' != null, your input will have a value the whole time, and that message will go away.
Another approach it could be setting the default value inside your input, like this:
<input name="name" type="text" value={this.state.name || ''} onChange={this.onFieldChange('name').bind(this)}/>
I know others have answered this already. But a very important factor here that may help other people experiencing similar issue:
You must have an onChange handler added in your input field (e.g. textField, checkbox, radio, etc). Always handle activity through the onChange handler.
Example:
<input ... onChange={ this.myChangeHandler} ... />
When you are working with checkbox you may need to handle its checked state with !!.
Example:
<input type="checkbox" checked={!!this.state.someValue} onChange={.....} >
Reference: https://github.com/facebook/react/issues/6779#issuecomment-326314716
Simple solution to resolve this problem is to set an empty value by default :
<input name='myInput' value={this.state.myInput || ''} onChange={this.handleChange} />
One potential downside with setting the field value to "" (empty string) in the constructor is if the field is an optional field and is left unedited. Unless you do some massaging before posting your form, the field will be persisted to your data storage as an empty string instead of NULL.
This alternative will avoid empty strings:
constructor(props) {
super(props);
this.state = {
name: null
}
}
...
<input name="name" type="text" value={this.state.name || ''}/>
I had the same problem.
the problem was when i kept the state info blank
const [name, setName] = useState()
I fixed it by adding empty string like this
const [name, setName] = useState('')
In my case, I was missing something really trivial.
<input value={state.myObject.inputValue} />
My state was the following when I was getting the warning:
state = {
myObject: undefined
}
By alternating my state to reference the input of my value, my issue was solved:
state = {
myObject: {
inputValue: ''
}
}
When you use onChange={this.onFieldChange('name').bind(this)} in your input you must declare your state empty string as a value of property field.
incorrect way:
this.state ={
fields: {},
errors: {},
disabled : false
}
correct way:
this.state ={
fields: {
name:'',
email: '',
message: ''
},
errors: {},
disabled : false
}
If the props on your component was passed as a state, put a default value for your input tags
<input type="text" placeholder={object.property} value={object.property ? object.property : ""}>
Set a value to 'name' property in initial state.
this.state={ name:''};
An update for this. For React Hooks use const [name, setName] = useState(" ")
Simply create a fallback to '' if the this.state.name is null.
<input name="name" type="text" value={this.state.name || ''} onChange={this.onFieldChange('name').bind(this)}/>
This also works with the useState variables.
I believe my input is controlled since it has a value.
Now you can do this two ways the best way is to have a state key to each input with 1 onChange handler. If you have checkboxes you will need to write a separate onChange handler.
With a Class component you would want to write it like this πŸ‘‡
import React from 'react';
export default class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {
myFormFields: {
name: '',
dob: '',
phone: ''
}
}
this.onFormFieldChange = this.onFormFieldChange.bind(this)
}
// Always have your functions before your render to keep state batches in sync.
onFormFieldChange(e) {
// No need to return this function can be void
this.setState({
myFormFields: {
...this.state.myFormFields,
[e.target.name]: e.target.value
}
})
}
render() {
// Beauty of classes we can destruct our state making it easier to place
const { myFormFields } = this.state
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={myFormFields.name} onChange={this.onFormFieldChange}/>
<input name="dob" type="date" value={myFormFields.dob} onChange={this.onFormFieldChange}/>
<input name="phone" type="number" value={myFormFields.phone} onChange={this.onFormFieldChange}/>
</form>
)
}
}
export default MyForm;
Hope that helps for a class but the most performative and what the newest thing the devs are pushing everyone to use is Functional Components. This is what you would want to steer to as class components don't intertwine well with the latest libraries as they all use custom hooks now.
To write as a Functional Component
import React, { useState } from 'react';
const MyForm = (props) => {
// Create form initial state
const [myFormFields, setFormFields] = useState({
name: '',
dob: '',
phone: ''
})
// Always have your functions before your return to keep state batches in sync.
const onFormFieldChange = (e) => {
// No need to return this function can be void
setFormFields({
...myFormFields,
[e.target.name]: e.target.value
})
}
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={myFormFields.name} onChange={onFormFieldChange}/>
<input name="dob" type="date" value={myFormFields.dob} onChange={onFormFieldChange}/>
<input name="phone" type="number" value={myFormFields.phone} onChange={onFormFieldChange}/>
</form>
)
}
export default MyForm;
Hope this helps! 😎
In short, if you are using class component you have to initialize the input using state, like this:
this.state = { the_name_attribute_of_the_input: "initial_value_or_empty_value" };
and you have to do this for all of your inputs you'd like to change their values in code.
In the case of using functional components, you will be using hooks to manage the input value, and you have to put initial value for each input you'd like to manipulate later like this:
const [name, setName] = React.useState({name: 'initialValue'});
If you'd like to have no initial value, you can put an empty string.
In my case component was rerendering and throwing A component is changing an uncontrolled input of type checkbox to be controlled error. It turned out that this behaviour was a result of not keeping true or false for checkbox checked state (sometimes I got undefined). Here what my faulty component looked like:
import * as React from 'react';
import { WrappedFieldProps } from 'redux-form/lib/Field';
type Option = {
value: string;
label: string;
};
type CheckboxGroupProps = {
name: string;
options: Option[];
} & WrappedFieldProps;
const CheckboxGroup: React.FC<CheckboxGroupProps> = (props) => {
const {
name,
input,
options,
} = props;
const [value, setValue] = React.useState<string>();
const [checked, setChecked] = React.useState<{ [name: string]: boolean }>(
() => options.reduce((accu, option) => {
accu[option.value] = false;
return accu;
}, {}),
);
React.useEffect(() => {
input.onChange(value);
if (value) {
setChecked({
[value]: true, // that setChecked argument is wrong, causes error
});
} else {
setChecked(() => options.reduce((accu, option) => {
accu[option.value] = false;
return accu;
}, {}));
}
}, [value]);
return (
<>
{options.map(({ value, label }, index) => {
return (
<LabeledContainer
key={`${value}${index}`}
>
<Checkbox
name={`${name}[${index}]`}
checked={checked[value]}
value={value}
onChange={(event) => {
if (event.target.checked) {
setValue(value);
} else {
setValue(undefined);
}
return true;
}}
/>
{label}
</LabeledContainer>
);
})}
</>
);
};
To fix that problem I changed useEffect to this
React.useEffect(() => {
input.onChange(value);
setChecked(() => options.reduce((accu, option) => {
accu[option.value] = option.value === value;
return accu;
}, {}));
}, [value]);
That made all checkboxes keep their state as true or false without falling into undefined which switches control from React to developer and vice versa.
For people using Formik, you need to add a default value for the specific field name to the form's initialValues.
This generally happens only when you are not controlling the value of the filed when the application started and after some event or some function fired or the state changed, you are now trying to control the value in input field.
This transition of not having control over the input and then having control over it is what causes the issue to happen in the first place.
The best way to avoid this is by declaring some value for the input in the constructor of the component.
So that the input element has value from the start of the application.
Please try this code
import React from "react";
class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = { name: "" };
this.onFieldChange = this.onFieldChange.bind(this);
}
onFieldChange(e) {
this.setState({[e.target.name]: e.target.value});
}
render() {
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={this.state.name} onChange={this.onFieldChange} />
</form>
);
}
}
export default MyForm;
In my case there was spell mistake while setting the state which was causing defined value to be undefined.
This is my default state with value
const [email, setEmail] = useState(true);
my mistake was-
setEmail(res?.data?.notificationSetting.is_email_notificatio);
and the solution is -
setEmail(res?.data?.notificationSetting.is_email_notification);
last char was missing
I had the same issue with type='radio'
<input type='radio' checked={item.radio} ... />
the reason was that item.radio is not always true or false, but rather true or undefined, for example. Make sure it’s always boolean, and the problem will go away.
<input type='radio' checked={!!item.radio} ... />
source
For dynamically setting state properties for form inputs and keeping them controlled you could do something like this:
const inputs = [
{ name: 'email', type: 'email', placeholder: "Enter your email"},
{ name: 'password', type: 'password', placeholder: "Enter your password"},
{ name: 'passwordConfirm', type: 'password', placeholder: "Confirm your password"},
]
class Form extends Component {
constructor(props){
super(props)
this.state = {} // Notice no explicit state is set in the constructor
}
handleChange = (e) => {
const { name, value } = e.target;
this.setState({
[name]: value
}
}
handleSubmit = (e) => {
// do something
}
render() {
<form onSubmit={(e) => handleSubmit(e)}>
{ inputs.length ?
inputs.map(input => {
const { name, placeholder, type } = input;
const value = this.state[name] || ''; // Does it exist? If so use it, if not use an empty string
return <input key={name} type={type} name={name} placeholder={placeholder} value={value} onChange={this.handleChange}/>
}) :
null
}
<button type="submit" onClick={(e) => e.preventDefault }>Submit</button>
</form>
}
}

Categories