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

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'
}

Related

How to remove of MUI 5 TextField label without having notched style?

I'm working on replacing the DatePicker component in our app with the new #mui DatePicker, and I'm having some trouble getting the TextField to render without the floating label and the notched input style. Here is my latest attempt:
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DatePicker
onError={(reason, value) => console.log(reason, value)}
disableOpenPicker
className={styles.datepicker}
disableMaskedInput
onChange={() => undefined}
onAccept={handleAccept}
open={datePickerVisible}
value={getSafeDate(value) as Date}
onClose={partial(handleDatepickerVisibilityChange, false)}
{...datepickerProps}
renderInput={(params) => (
<TextField
id={id}
{...inputProps}
{...params}
onChange={handleInputChange}
error={errorText !== null}
helperText={errorText}
onBlur={handleValueChange}
onKeyPress={handleKeyPress}
hiddenLabel
size='small'
fullWidth
/>
)}
/>
</LocalizationProvider>
I've tried many different combinations for TextField props, such as adding InputLabelProps={{shrink:false}}, InputLabelProps={{shrink:true}}, and inputProps={{notched:false}} but always end up looking like this:
Does anyone have an idea of how to correct this, or if it's possible?
Thanks!
The issue was fixed in release v5.4.0
​[TextField] Remove notch when no label is added (#30560) #alisasanib
Updating to v5.4.0 should solve the issue.

React material UI autocomplete is not working with the formik

I have this code snippet, which is written by someone else.
<FormControl className={classes.formControl}>
<InputLabel id="combo-box-demo">
{values.type === "forAllCustomers" ? "" : ""}
</InputLabel>
<Autocomplete
id="combo-box-demo"
name="customerId"
onBlur={handleBlur}
onChange={handleChange}
value={values.customerId}
options={agents}
getOptionLabel={(option) => option.name}
disabled={values.type === "forAllCustomers"}
renderTags={(value, getTagProps) => {
filteredAgents(values.type).map(
(option, agentId) => (
<Chip
variant="outlined"
label={option.name}
// size="small"
{...getTagProps({ agentId })}
/>
)
);
}}
renderInput={(params) => (
<TextF
{...params}
variant="outlined"
label="Customer"
placeholder="Select"
name="agentId"
/>
)}
/>
</FormControl>
Here we load bunch of agents. If user pick one agent, that agents id should set as the customerId.
Here we use formik, so onBlur={handleBlur} onChange={handleChange} is controlled by the formik.
I tried by setting value to values.customerId But it seems not working and also I am getting an error in the console saying
index.js:1 Material-UI: The getOptionLabel method of Autocomplete
returned undefined instead of a string for "".
How do I fix this issue?
Anyhelp!
Thanks in advance. =)
See, the signature of the function onChange of AutoComplete is:
function(event: object, value: T | T[], reason: string) => void
However, signature of handleChange of Formik is
handleChange: (e: React.ChangeEvent<any>) => void
The problem is that simply passing onChange={handleChange} will not do what you think.
See, if you put, before the return statement a console.log(values), you'll see your initialValues object. However, a change in the Autocomplete will fill this object with strange combo-box-demo-option-0 1, 2 and so on. This is because how the Autocomplete component handles the combobox and the name and id properties. According to Formik, handleChange will look for the name or id to operate, and none have the correspondence you want.
Enough said, to fix your problem, you have to use another method provided by Formik: setFieldValue
Your Autocomplete should look something on the lines of:
<Autocomplete
id="combo-box-demo"
name="customerId"
onChange={(e, v) => {
setFieldValue("name", v?.name || "");
setFieldValue("customerId", v?.id || "");
}}
value={values}
options={agents}
getOptionLabel={(option) => option.name || ''}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Combo box" variant="outlined" />
)}
/>;
You will not need the useState because you are not handling yourself any state changes. A regular javascript object will be enough.
Please check the agents you are getting. There might be an issue with your agents data coming from API RESPONSE or from anywhere else. According to Material-UI, the parameter you pass to options should be in an Array but your one might be an Object.
Please convert the Data type of agents to Array instead of Object if it is not in an Array and it will work!
<Autocomplete
id="combo-box-demo"
name="customerId"
onBlur={handleBlur}
onChange={handleChange}
value={values.customerId}
options={agents} //This should be in An Array
getOptionLabel={(option) => option.name} //Then access name
disabled={values.type === "forAllCustomers"}
/>
Please check the Official Docs of Material-UI https://material-ui.com/components/autocomplete/

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,
}}
/>

dynamic label width textfield outlined material ui react

I have a textfield variant outlined, and there I have a dynamic label, the problem is that when it changes the top line in width remains the same as the first time
<TextField
id="debtorIin"
name="debtorIin"
label={debtorType === "pvt" ? "Ф.И.О.:" : "Наименование организации:"}
disabled={debtorFullInfo && true}
className={classes.textField}
value={debtorIin}
helperText={touched.debtorIin ? errors.debtorIin : ""}
error={touched.debtorIin && Boolean(errors.debtorIin)}
onChange={change.bind(null, "debtorIin")}
margin="normal"
variant="outlined"
/>
(source: imggmi.com)
(source: imggmi.com)
I think it happens because it won't recalculate the width on property change, you can solve that by creating two different TextField for it.
First, you need one that contains all the common props.
const MyTexField = ({ label, ...props }) => (
<TextField
id="debtorIin"
name="debtorIin"
label={props.label}
disabled={props.debtorFullInfo && true}
className={props.classes.textField}
value={props.debtorIin}
helperText={props.touched.debtorIin ? props.errors.debtorIin : ""}
error={props.touched.debtorIin && Boolean(props.errors.debtorIin)}
onChange={change.bind(null, "debtorIin")}
margin="normal"
variant="outlined"
/>
);
Then, you can use that component:
<MyTextField label="Ф.И.О.:" {...props} />

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