MUI TextField not accepting pattern - reactjs

I want to make Material UI TextField to only accept number values, in the MUI documentation the solution is as following:
<TextField inputProps={{ inputMode: 'numeric', pattern: '[0-9]*' }} />
However this is for the version 5 of MUI, and in my case I'm using the version 4, so I tried as following:
<TextField
InputProps={{
inputProps: {
inputMode: "numeric",
pattern: "[0-9]*"
}
}}
/>
But for some reason, this is not working, and I can still type values other than numbers in the input.
Using input="number" is not an option, as I don't want to keep the 0 when the input is empty, neither I want the stepper to be visible.
Full example is in this sandbox: https://codesandbox.io/s/mui4-forked-0j98er?file=/src/App.js:136-408
How can I solve this ?

You can use controlled input and clean value from non-numeric characters
export default function MyComponent() {
const [inputValue, setInputValue] = useState("");
function onChange(e) {
setInputValue(e.target.value.replace(/\D/g, ""));
}
return (
<TextField
label="number input"
variant="outlined"
color="secondary"
fullWidth
value={inputValue}
onChange={onChange}
inputProps={{
maxLength: 5
}}
/>
);
}
I was inspired by #Dmitriif's answer because it uses less code. But I tweaked it a bit.
live demo
However, the min: 0 doesn't work
export default function IconButtons() {
return (
<TextField
label="number input"
variant="outlined"
color="secondary"
fullWidth
inputProps={{
type: "text",
inputMode: "numeric",
pattern: "d*",
min: 0,
maxLength: 5
}}
/>
);
}

TextField in mui v4 also has inputProps property which can help you to apply desired attributes to the input element. However, you will need to set another property type="number" to make the component work correctly in your case:
<TextField
label="number input"
variant="outlined"
color="secondary"
fullWidth
type="number"
inputProps={{
min: 0,
maxLength: 5,
inputMode: "numeric",
pattern: "[0-9]*"
}}
/>
Demo

Related

PrimeReact number input field with react-hook-form

I currently have the following code in my application:
<Controller defaultValue={0.0} name={"create_lng"}
control={createControl} rules={{
required: {value: true, message: t("pleaseSiteLng")}
}}
render={({field, fieldState}) => (
<InputNumber minFractionDigits={2}
mode={"decimal"}
className={classNames(
{"p-invalid": createErrors.create_lng})}
id={field.name} {...field} />
)}/>
Here I would now expect to be able to enter decimal numbers as defined.
But as soon as I enter anything in the input field, even numbers, the value changes to NaN and is displayed.
This only occurs with the InputNumber component, all other components can be filled without problems and also display the desired values.
I have seen that there is a property from react-hook-form "valueAsNumber", but I haven't found anything how to use it in a controller.
Does anyone here know how I can solve the problem?Does anyone here know how I can solve the problem?
I have updated this ticket: https://github.com/primefaces/primereact/issues/2547
I think there needs to be showcase example on how to use InputNumber with React Hook Forms if it is not straightforward like you are seeing.
Edit 07/30/2022:
I have it working and here are two examples:
Price example must be between 0 and 250,000.
<Controller name="price" control={control} rules={{ required: 'Price is required.', min: 0, max: 250000 }} render={({ field, fieldState }) => (
<>
<label htmlFor={field.name} className={classNames({ 'p-error': errors.price })}>Price*</label>
<InputNumber id={field.name} ref={field.ref} value={field.value} onBlur={field.onBlur} onValueChange={(e) => field.onChange(e)} mode="currency" currency="USD" locale="en-US" inputClassName={classNames({ 'p-invalid': fieldState.error })} />
{getFormErrorMessage(fieldState)}
</>
)} />
Year example must be between 1970-2030:
<Controller name="year" control={control} rules={{ required: 'Year is required.', min: 1970, max: 2050 }} render={({ field, fieldState }) => (
<>
<label htmlFor={field.name} className={classNames({ 'p-error': errors.year })}>Year*</label>
<InputNumber id={field.name} ref={field.ref} value={field.value} onBlur={field.onBlur} onValueChange={(e) => field.onChange(e)} useGrouping={false} inputClassName={classNames({ 'p-invalid': fieldState.error })} />
{getFormErrorMessage(fieldState)}
</>
)} />
I encountered the same issue when working with Primereact InputNumber and Formik.
In my case the reason for unexpected behavior of InputNumber component is primereact custom onChange method of InputNumber:
onChange?(e: InputNumberChangeParams): void
interface InputNumberChangeParams {
originalEvent: React.SyntheticEvent;
value: number | null;
}
(Compared to InputText onChange property: onChange?: ChangeEventHandler<HTMLInputElement> | undefined )
formik.handleChange(e) expects e: React.ChangeEvent<any> which means I can't pass (e: InputNumberChangeParams) to the function. The solution for me was to use another function to handle the change and work only with e.value which is provided by InputNumber onChange method.
onChange={(e): void => {
formik.setFieldValue("fieldName", e.value);
}}

How to override autocomplete/autofill in material-ui autocomplete - React JS

I am using material-ui autocomplete ( https://mui.com/components/autocomplete/#free-solo ).
It's working fine, demo is here : https://codesandbox.io/s/0v9v9?file=/demo.tsx
by default Text input is showing autoComplete='off' but i want to change it to autoComplete='new-something' but it's not working and autoComplete='new-something' is showing as parent dev attribute instead of Input
I used this code
<TextField
{...params}
inputProps={{
...params.inputProps,
autoComplete: 'new-something',
}}
/>
But it's not working. In input it's still showing autocomplete="off" as input attribute.
As you can see in the doc https://mui.com/api/text-field/#props there is two props with the same name
inputProps: Attributes applied to the input element.
InputProps: Props applied to the Input element.
For autocomplete attribute you need inputProps
<TextField
{...params}
label="Search input"
InputProps={
...params.InputProps,
type: 'search',
}}
inputProps={{
autocomplete: 'something'
}}
/>
Here a working exanple in the codesanbox https://codesandbox.io/s/freesolo-material-demo-forked-8g2n1?file=/demo.tsx

Render "outlined" input when using react-text-mask with Material-UI inputs

I'm unable to figure out how to render outlined input type(one of the standard Material-UI input styles when used with text mask).
I copied the code sample from here: https://material-ui.com/components/text-fields/
But it only gives a sample for regular(underlined) input but nothing for outlined.
This is what i'm trying to do but it doesnt work:
const ExpirationMask = props => {
const { inputRef, ...other } = props
return <MaskedInput
{...other}
ref={ref => {inputRef(ref ? ref.inputElement : null)}}
mask={[/\d/, /\d/,'/' ,/\d/, /\d/]}
placeholderChar={'\u2000'}
/>
}
<FormControl
variant='outlined' //this doesnt work
fullWidth
>
<InputLabel>Expiration</InputLabel>
<Input
value={ccExpiration}
onChange={(e, v) => setCCExpiration(e.target.value)}
placeholder='MM/YY'
variant='outlined' //this doesnt work either
inputComponent={ExpirationMask}
/>
</FormControl>
I found a solution for it. I didn't realize that TextField is just a wrapper for the Input.
There is also another wrapper for the Input which is called OutlinedInput. So this was exactly what I ended up using:
<FormControl
fullWidth
margin='dense'
>
<InputLabel
classes={{ root: classes.expInputRoot }}
error={ccExpiration.trim().length < 5}
color='primary'>
Expiration
</InputLabel>
<OutlinedInput
value={ccExpiration}
onChange={(e, v) => setCCExpiration(e.target.value)}
label="Expiration"
placeholder='MM/YY'
error={ccExpiration.trim().length < 5}
inputComponent={ExpirationMask}
/>
</FormControl>
In doing so i encountered another problem however with an InputLabel that wasn't aligning properly(not sure if it is a bug or what), so i ended up manually changing styles for it like this:
expInputRoot: {
margin:'-8px 0 0 14px'
}

How to make autocomplete field of material UI required?

I have tried a couple of ways in order to make the material UI's autocomplete field of type required but I am not getting the behavior that I wanted. I had encapsulated my field inside react hook form <Controller/> yet no luck. I want to trigger message 'Field is mandatory' on submit when nothing is added to the field.
Below is the code snippet, I have not removed comments so that it becomes a bit easier for others to understand the approach that I had followed earlier -
<Controller
name="displayName"
as={
<Autocomplete
value={lists}
multiple
fullWidth
size="small"
limitTags={1}
id="multiple-limit-lists"
options={moduleList}
getOptionLabel={(option) => option.displayName}
renderInput={(params,props) => {
return (
<div>
<div className="container">
<TextValidator {...params} variant="outlined" label="Display Name*" className="Display Text"
name="displayName" id="outlined-multiline-static"
placeholder="Enter Display-Name" size="small"
onChange={handleDisplay}
// validators={['required']} this and below line does throw a validation but the problem is this validation stays on the screen when user selects something in the autocomplete field which is wrong.
// errorMessages={['This field is required']}
// withRequiredValidator
/>
</div>
</div>
)
}}
/>
}
// onChange={handleDisplay}
control={control}
rules={{ required: true }}
// required
// defaultValue={options[0]}
/>
<ErrorMessage errors={errors} name="displayName" message="This is required" />
You can use the following logic to get it worked. Though this might not be the best solution but works.
<Autocomplete
renderInput={(params) => (
<TextField
{...params}
label={value.length === 0 ? title : title + " *"} //handle required mark(*) on label
required={value.length === 0}
/>
)}
/>
I tried using the built in required in textfield for autocomplete, and it works like a charm. Maybe you can use this as a reference.
<Autocomplete
renderInput={(params) => {
<TextField {...params} required />
}
// Other codes
/>
Since you are rendering <TextValidator>, you should apply mandatory(required) attribute to that component not on <AutomComplete>.
Try this if your Material UI version is v5
<TextField
{...params}
required
label="Tags"
value={value}
InputProps={{
...params.InputProps,
required: value.length === 0,
}}
/>

How Can I Mask My Material-UI TextField?

I have a TextField for phone numbers in a short form. And then i want to mask this form field like (0)xxx xxx xx xx.
I'm trying to use react-input-mask plugin with Material-UI. But if i want to change input value, this is not updating the my main TextField.
<TextField
ref="phone"
name="phone"
type="text"
value={this.state.phone}
onChange={this.onChange}
>
<InputMask value={this.state.phone} onChange={this.onChange} mask="(0)999 999 99 99" maskChar=" " />
</TextField>
Actually, I couldn't find any documentation for masking with Material-UI. I'm trying to figure out how can i use with another plugins.
Update
versions: material-ui 0.20.2, react-input-mask 2.0.4
Seems like the API changed a bit:
<InputMask
mask="(0)999 999 99 99"
value={this.state.phone}
disabled={false}
maskChar=" "
>
{() => <TextField />}
</InputMask>
Demo
Original
This should do the trick:
<TextField
ref="phone"
name="phone"
type="text"
value={this.state.phone}
onChange={this.onChange}
>
<InputMask mask="(0)999 999 99 99" maskChar=" " />
</TextField>
Demo:
For current version of Material-UI and react-input-mask, the following answer worked:
<InputMask
mask="(1)999 999 9999"
value={self.state.inputValue}
onChange={this.getTextFieldValue}
className={this.props.classes.textField}
>
{() => <TextField
id={attribute}
label={attribute}
name={attribute}
className={this.props.classes.textField}
margin="normal"
type="text"
/>}
</InputMask>
This is valid for current version of react-input-mask and material-ui:
<InputMask
mask="(0)999 999 99 99"
value={this.state.phone}
onChange={this.onChange}
>
{() => <TextField />}
</InputMask>
Question:
codesandbox.io/s/q8v1259oq6 please check this my label test floatingLabelText is hidden How I solve. – Thilina Sampath
Work Around:
You can controll Label Position with "floatingLabelFixed" prop. At your handleChange look to state input value.
...when create with value:
constructor(props) {
super(props);
let value = props && props.value ? props.value : '';
let floatingLabelFixed = !!value;
this.state = {
value,
floatingLabelFixed,
};
this.handleChange = this.handleChange.bind(this);
}
...when edit (onChange):
handleChange(event) {
let value = event && event.target && event.target.value ? event.target.value : '';
let floatingLabelFixed = !!value;
this.setState({
value,
floatingLabelFixed
});
}
...your input:
<TextField
onChange={this.handleChange}
value={this.state.value}
floatingLabelFixed={this.state.floatingLabelFixed}/>
You can also use https://github.com/text-mask/text-mask. Seems like a solid project, even though it is not maintained anymore.
It provides a demo page for testing stuff and some addons that I successfully used to create a custom price input field (with material ui TextField component).
There's also an example codesandbox that I found somethere in the docs page, I believe.
Copy/pasting the codesandbox example here (you would need to adjust the mask to your needs):
// ... React imports.
import MaskedInput from "react-text-mask";
import createAutoCorrectedDatePipe from "text-mask-addons/dist/createAutoCorrectedDatePipe";
const autoCorrectedDatePipe = createAutoCorrectedDatePipe("mm/dd/yyyy", {
minYear: 1900,
maxYear: 2099
});
function TextMaskCustom(props) {
const { inputRef, ...other } = props;
return (
<MaskedInput
{...other}
ref={ref => {
inputRef(ref ? ref.inputElement : null);
}}
mask={[/\d/, /\d/, "/", /\d/, /\d/, "/", /\d/, /\d/, /\d/, /\d/]}
placeholderChar={"\u2000"}
pipe={autoCorrectedDatePipe}
guide
keepCharPositions
/>
);
}
// ...
<div>
<TextField
label="react-text-mask"
value={values.textmask}
onChange={handleChange("textmask")}
InputProps={{
inputComponent: TextMaskCustom
}}
helperText="mm/dd/yyyy"
variant="outlined"
margin="dense"
/>
</div>
<InputMask
mask="99999" // Format you need implemented
value={cellNumber}
onChange={this.inputHandler}
placeholder="Cell Number"
name="cellNumber"
required disableUnderline
style={style.inputfeild}
maskChar= {'_'}> // To display when there is no character typed
{(inputProps) =>
<Input {...inputProps}/>}
</InputMask>
Just provide all your props to InputMask and then pass them as input props to the call back method in which you display your Textfield or Input field and it should work just fine.

Resources