How to use Material-ui#next TextField error props - material-ui

I want to use Material-UI Next textfield error props link, the props type is boolean. The previous version of Material-UI props name is errorText and the props type is node link.
Textfield Material-UI previous version using errorText props :
<TextField
name='name'
floatingLabelText='Name'
hintText='Type your name'
value={this.state.fields.name}
onChange={this.onChange}
errorText={this.state.error}
/>
With errorText in Material-UI previous version, the code works good for displaying an error state.
Textfield Material-UI Next using error props:
<TextField
name='name'
label='Name'
placeholder='Type your name'
value={this.state.fields.name}
onChange={this.onChange}
error={true} //only accept true or false value
/>
On Material-UI Next errorText props changed to error with boolean type and only accept true or false value. If i set the error props to true, the textfield displaying error state at any time. I just want to displaying error state under certain conditions.
How can i use error state this.state.error on Material-UI Next textfield?

Using a react component state, one can store the TextField value and use that as an indicator for an error. Material-UI exposes the error and helperText props to display an error interactively.
Take a look at the following example:
<TextField
value={this.state.text}
onChange={event => this.setState({ text: event.target.value })}
error={text === ""}
helperText={text === "" ? 'Empty field!' : ' '}
/>

I add an example that does not shows an error when the value is empty and validates a regular expression (MAC Address).
<TextField id="macAddress" label="MAC Address" name="macAddress"
value={this.state.macAddress}
onChange={this.handleChange}
error={this.state.macAddress !== "" && !this.state.macAddress.match("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$")}
helperText={this.state.macAddress !== "" && !this.state.macAddress.match("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$") ? 'MAC Address must be a 6-bytes string.' : ' '}
/>

Related

Autocomplete how do we resolve error -Material-UI: The key `underline` provided to the classes prop is not implemented in ForwardRef(InputBase)

Hi I tried to use Textbox instead of textfield, and I get following error.
I do not get error with TextField, but had to use Textbox for some reasons.
All the functionality works fine, but every-time I type I see this error in console
Autocomplete:
<Autocomplete
popupIcon
className={classes.searchFieldAc}
...
inputValue={searchValue}
noOptionsText="No matching results"
onInputChange={(e, value) =>handleChange(value)}
options={suggestions}
onSelect={() => selectHandleClick(searchValue)}
renderInput={(params) => (
<Textbox
{...params}
// classes={{ root: classes.customTextField }}
//className={classes.customTextField}
placeholder={fieldName}
label={fieldName}
variant="outlined"
fullWidth
/>
)}
ListboxProps={{
style: {
maxHeight: '15rem',
fontFamily: '"Open Sans", sans-serif',
fontSize: '16px',
},
}}
size="small"
/>
Error:
mergeClasses.js?653b:36 Material-UI: The key underline provided to the classes prop is not implemented in ForwardRef(InputBase).
You can only override one of the following: root,formControl,focused,disabled,adornedStart,adornedEnd,error,marginDense,multiline,colorSecondary,fullWidth,input,inputMarginDense,inputMultiline,inputTypeSearch,inputAdornedStart,inputAdornedEnd,inputHiddenLabel.

MUI V5 DateTimePicker not displaying the expected Yup validation error message

I am building a form with Yup, React Hook Form and, MUI V5. I am using a DateTimePicker from MUI V5 but it is not displaying Yup's error messages as expected.
Ideally, the errors should display as follow:
Invalid format message: Invalid date format. (mm/dd/yyyy hh:mm am or
pm)
Required field's message: The field cannot be left blank.
Additionally, when there is a validation error or when the field
loses its focus it does not turn red.
So, if the field is empty and I press the submit button, the invalid format message is displayed.
here is the schemas code:
const schema = yup.object().shape({
name: yup
.string()
.required("Please enter your name. The field cannot be left blank."),
date: yup
.date()
.transform(parseDateString)
.typeError("Invalid date format. (mm/dd/yyyy hh:mm am or pm)")
.nullable()
.required("Please enter a valid date. The field cannot be left blank.")
});
I have tried moving nullable() to every different position and the result still the same.
I have commented nullable() and typeError and I get the default error from date (date must be a date type, but the final value was: Invalid Date.)
Here is a working example
The Invalid Date error comes from the date-fns parser function that is in the parseDateString function called in the Yup transform method.
Yup transform method is used to transform incoming date from the input field, in this case it's MUI's DateTimePicker.
That being sad it has nothing to do with this error and the problem is in the DatePicker component. Make note of the TextField and {...params} destructuring. Since the error prop was before we destructure params it was overwritten.
Here is a working example.
const CalPicker = ({ helperText, name, label, control, required, error }) => {
const [value, setValue] = React.useState();
return (
<Stack sx={{ mt: 2 }}>
<LocalizationProvider dateAdapter={DateAdapter}>
<Controller
name={name}
control={control}
render={({ field }) => (
<DateTimePicker
{...field}
renderInput={(params) => (
<TextField
required={required}
{...params}
helperText={helperText}
error={error}
/>
)}
label={label}
value={value}
onChange={(newValue) => {
field.onChange(newValue);
setValue(newValue);
}}
/>
)}
/>
</LocalizationProvider>
</Stack>
);
};
add under LocalizationProvider:
{error ? <div className="error">{error}</div> : null}

Unable to see results with AsyncTypeahead with multiple option and renderInput

I'm trying to use a custom Input component on a Typeahead with the multiple option set. I see in the docs it says to "handle the refs" correctly, but I see no examples of how this is done. I'm not sure what to pass into referenceElementRef. Everything I've tried so far just doesn't render the options as I type. I see them in the DOM, but the opacity of the .rbt-menu is set to 0, so they're basically hidden.
Here's my code so far:
const divRef = React.useRef(null);
return (
<Col>
<div ref={divRef}>
<span className="uppercase">
<FormattedMessage id="d.customer" defaultMessage="Customer" tagName="h4" />
</span>
<AsyncTypeahead
multiple
id="customer-filter-input"
inputProps={{
'aria-label': 'Customer search',
style: { fontSize: '14px' },
}}
key={'customer-input'}
minLength={4}
isLoading={props.isLoadingcustomersSuggestions}
delay={300}
onSearch={(term: string) => handleFilterInputs(term, 'customers')}
size={'lg'}
options={dataSource}
labelKey={'defaultMessage'}
placeholder={intl.formatMessage({
id: 'companyName',
defaultMessage: 'Company name',
})}
onChange={(filterItem: any) => handleAutocompleteUpdate(filterItem, 'customer')}
renderInput={({ inputRef, referenceElementRef, ...inputProps }: any) => (
<Input
{...inputProps}
style={{ position: 'relative' }}
ref={(input: any) => {
inputRef(input);
referenceElementRef(divRef); // What do I put here?
}}
/>
)}
/>
</div>
</Col>
);
And this is what renders in the DOM after I type in the Typeahead and get results:
Any ideas or working examples of Typeahead using multiple and renderInput together?
EDIT:
Here's a codesandbox of what I'm seeing. I also see that the problem is also happening when multiple is NOT set. It seems to be an issue with using renderInput. Is it required that I also use renderMenu?
https://codesandbox.io/s/react-bootstrap-typeahead-async-pagination-example-forked-3kz3z
If you upgrade the typeahead version in your sandbox to the latest version (v5.1.1) and pass the input element to referenceElementRef, it works (note that you need to type some characters into the input for the menu to appear):
// v5.0 or later
renderInput={({ inputRef, referenceElementRef, ...inputProps }) => (
<Input
{...inputProps}
ref={(input) => {
inputRef(input);
referenceElementRef(input);
}}
/>
)}
The menu is rendered in relation to the referenceElementRef node by react-popper. In most common cases, the reference node will be the input itself. The reason there's both an inputRef and a referenceElementRef is for more complex cases (like multi-selection) where the menu needs to be rendered in relation to a container element around the input.
If using v4 of the component, the approach is similar, but the ref to use is simply called ref:
// v4
renderInput={({ inputRef, ref, ...inputProps }) => (
<Input
{...inputProps}
ref={(input) => {
inputRef(input);
ref(input);
}}
/>
)}

Material UI Tabs no selected tab

I'm trying to use Material UI Tabs for navigation. However, there are routes in my application that match none of the tabs. When I pass a value to the Tabs component that does not match any of the child tab values, I get a warning about an invalid value.
I created a hidden tab will a value of null as a work-around.
Is it possible to disable this warning about an invalid tab value?
Can tabs in Material UI have no selection?
Thanks
The value of the currently selected Tab. If you don't want any selected Tab, you can set this property to false.
From: https://material-ui.com/api/tabs/
What I ended up doing is creating a switch statement with valid tab values, and if windows.location.pathname doesn't match any of them have the default return false.
Example Routes:
class Routes extends Component {
render() {
return (
<Switch>
<Route path={'/test2'} component={Test2} />
<Route path={'/test3'} component={Test3} />
<Route exact path={'/'} component={Test} />
</Switch>
);
}
}
Example NavBar:
checkPathnameValue() {
const { pathname } = window.location;
switch (pathname) {
case '/test2':
case '/test3':
break;
default:
return false;
}
return pathname;
}
render() {
const { classes } = this.props;
const tabValue = this.checkPathnameValue();
return (
<div className={classes.root}>
<AppBar position={'static'}>
<Toolbar>
<Tabs value={tabValue}>
<Tab
label={'Test 2'}
value={'/test2'}
to={'/test2'}
component={Link}
/>
<Tab
label={'Test 3'}
value={'/test3'}
to={'/test3'}
component={Link}
/>
</Tabs>
</Toolbar>
</AppBar>
</div>
);
}
Seems like setting the value property of Tabs to false will not show any warning and will deselect all the tabs correctly.
Philip's solution works perfectly, here I am just removing the need for the switch case.
In my case, I only had one tab (Login) where I wanted no tab to be selected since it is a button rather than a tab.
Here's what I did to solve this:
<Tabs value={this.state.content !== "login" ? this.state.content : false} onChange={(event, newValue) => { this.setState({content: newValue}) }}>
<Tab value="home" label="Home" wrapped />
<Tab value="tab1" label="Tab 1" />
<Tab value="tab2" label="Tab 2" />
</Tabs>
on another part of my AppBar I had a Login button:
<Button onClick={(event, newValue) => { this.setState({content: "login"}) }}>Login</Button >
Similarly to Philips's answer, the key is in {this.state.content !== "login" ? this.state.content : false} which prevents Tabs from being rendered with "login" value. Instead, it is given the value "false" which is allowed and does not invoke the warning.
I also experienced this issue a while back and follow the same pattern.
E.g.,
return <Tabbar value={value ?? false} onChange={(event: React.ChangeEvent<{}>, value: any) => onChange(value)}>{tabs}</Tabbar>
Toggle Effect
To get a toggle effect the listener will need to be placed on the individual <Tab onClick/> events as <Tabs onChange> will not trigger when clicking the same button multiple times.
const Container = ()=>{
const [currentTab,setCurrentTab] = React.useState<string|false>('a')
const handleChange = (val: string) =>
setCurrentTab(val === currentTab ? false : val)
return <Tabs value={currentTab}>
<Tab value='a' label='a' onClick={()=>handleChange('a')}/>
<Tab value='b' label='b' onClick={()=>handleChange('b')}/>
</Tabs>
}

Getting a dialog on click of Edit Button on admin-on-rest

I am working on an application using admin-on-rest framework. For editing an entry on a Resource we provide XXXEdit, XXXShow, XXXCreate props to it. My requirement is that when I click on an Edit button in List view on any entry I should get a Dialog box with the parameters in XXXEdit instead of going to a new page. I tried doing this by using a Dialog in XXXEdit component
<Edit title={<RoleTitle />} {...props}>
<SimpleForm>
<Dialog
title="Dialog With Actions"
actions={actions}
modal={false}
open={true}
>
<TextInput source="id" />
<TextInput source="name" validate={required} />
.
.//some more fields
</Dialog>
</SimpleForm>
</Edit>
I get errors like The TextInput component wasn't called within a redux-form
If I use a DisabledInput then I get an error cannot read value of undefined
How do I go on with this?
I do not think you can use Simpleform for this. You will need to create a custom Form using Redux-Form. Look at the bottom answer that documents the final answer.
This might help you
How to richly style AOR Edit page
Instead of creating a page. You are creating a component that connects to the Redux state and displays as a dialog box.
I tried to resolve this using HOC and react-router.
I created a button using AOR button and provided a containerElement
containerElement={
<Link
key={record.id}
to={{
...{
pathname: `${basePath}/${encodeURIComponent(record.id)}`
},
...{ state: { modal: true } }
}}
/>
}
I created a route like this where DialogRoleEdit is an AOR edit component wrapped with a dialog HOC below .
<Route
exact
path="/roles/:id"
render={routeProps => {
return !!(
routeProps.location.state && routeProps.location.state.modal
) ? (
<Restricted authClient={authClient} location={routeProps.location}>
<div>
<RoleList resource={"roles"} {...routeProps} />
<DialogRoleEdit resource={"roles"} {...routeProps} />
</div>
</Restricted>
) : (
<Restricted authClient={authClient} location={routeProps.location}>
<RoleEdit resource={"roles"} {...routeProps} />
</Restricted>
);
}}
/>
Finally an HOC
handleClose = () => {
this.props.history.goBack();
};
render() {
const actions = [
<FlatButton label="Cancel" primary={true} onClick={this.handleClose} />
];
return (
<Dialog>
<WrappedComponent/>
</Dialog>
)
}
We need to provide edit prop for this resource in App.js
edit={DialogUserEdit}