React Admin - Cannot focus on an AutocompleteInput programmatically - reactjs

I am using React Admin and was trying to focus an AutocompleteInput but its not working for me. Sample code as follows
const CreateFormCustom = (props) => {
const fieldRef1 = useRef(null);
const fieldRef2 = useRef(null);
const fieldRef3 = useRef(null);
return (
<SimpleForm {...props} redirect={false} >
<ReferenceInput helperText={false} fullWidth label="Users" source="u_id" reference="v1/users">
<AutocompleteInput inputRef={fieldRef1} onSelect={() => {fieldRef2.current.focus();}} optionValue="u_id" optionText="u_name" />
</ReferenceInput>
<NumberInput inputRef={fieldRef2} source="t_qty" label="Quantity" helperText={false} onKeyDown={(e)=>{if(e.which==13||e.keyCode==13) fieldRef3.current.focus();}} />
<NumberInput inputRef={fieldRef3} source="t_price" label="Price" helperText={false} onKeyDown={(e)=>{if(e.which==13||e.keyCode==13) fieldRef1.current.focus();}} />
</SimpleForm>
)}
Other two fields focus working perfectly but when i am on last field and press enter it shows error that Uncaught TypeError: Cannot read property 'focus' of null

The inputRef parameter is used inside the AutocompleteInput component and the passed parameter is ignored:
https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx#L465

Related

Material UI Slider with React hook form

I'm having a hard time integrating material Ui Slider with React hook form. It's not registering the values. It's printing the value as undefined on console.log. Got an idea where I might be wrong?
<Controller
render={({ field: { value, onChange } }) => (
<CustomSlider
onChange={onChange}
value={value}
max={60}
marks={marks}
className={classes.slider}
defaultValue={10}
/>
)}
control={control}
name="slider"
/>
Here is codesandbox made by author of react-hook-form that contains many examples. Mui integration is also made.
According to example, you are supposted to do something like this:
<Controller
name="MUI_Slider"
control={control}
defaultValue={[0, 10]}
render={(props) => (
<Slider
{...props}
onChange={(_, value) => {
props.onChange(value);
}}
valueLabelDisplay="auto"
max={10}
step={1}
/>
)}
/>
Another question is in which part of your code are you trying to console.log() values.
You can use watch() method or
<button Click={() => console.log(getValues())}>get values</button>

react-datepicker with react-final-form

I'm using the react-datepicker inside the react-final-form. I'm using a template with multiple steps https://codesandbox.io/s/km2n35kq3v?file=/index.js. The problem is that I'm not able to integrate the datepicker inside the component. My Code looks like this:
return (
<Field name={props.name} parse={() => true}>
{props => (
<DatePicker
locale="de"
placeholderText="Datum eingeben"
selected={startDate}
dateFormat="P"
openToDate={new Date()}
minDate={new Date()}
disabledKeyboardNavigation
name={props.name}
value={startDate}
onChange={(date) => setStartDate(date)}
/>
)}
</Field>
);
Does anyone knows how I can use it so the data gets passed at the end of the form?
Best regards
I used the wizard form example you sent and added DatePicker similar to yours.
Check the wizard example
But basically, I changed your onChange method to actually use react-final-form field props. Now, it uses this.props.input.onChange, which updates the final form state value, and used this.props.input.value to set the selected state (you can then load initial values into final form):
const RenderDatePicker = ({ name, input, input: { value, onChange } }) => {
return (
<DatePicker
locale="de"
placeholderText="Datum eingeben"
dateFormat="P"
selected={value && isValid(value) ? toDate(value) : null} // needs to be checked if it is valid date
disabledKeyboardNavigation
name={name}
onChange={(date) => {
// On Change, you should use final-form Field Input prop to change the value
if (isValid(date)) {
input.onChange(format(new Date(date), "dd-MM-yyyy"));
} else {
input.onChange(null);
}
}}
/>
);
};
<div>
<label>Date of birth</label>
<Field
name="dateOfBirth"
component={RenderDatePicker}
validate={required}
/>
<Error name="dateOfBirth" />
</div>
Hopefully this helps you.

How to hide multiple fields in react-admin ShowView?

I am trying to hide a set of fields based on the value of another field but the following will not display the conditional fields ever:
export const ServiceShow = (props) => (
<ShowController {...props}>
{controllerProps =>
<ShowView component="div" {...props} {...controllerProps}>
<TabbedShowLayout>
<Tab label="General">
{controllerProps.record && controllerProps.record.maintenance &&
controllerProps.record.maintenance.active &&
<>
<Alert severity="warning">Maintenance period active</Alert>
<DateField label="Maintenance Start" src="maintenance.start" />
<DateField label="Maintenance End" srvc="maintenance.end" />
<TextField label="Maintenance Message" source="maintenance.msg" />
</>
}
</Tab>
</TabbedShowLayout>
</ShowView>
}
</ShowController>
);
The <Alert> is displayed just fine, but the Field components are not. I'm very new to React so probably a simple thing.
Note:If I put a single <TextField> as the conditional output then it will work but anything inside a React.Fragment or <div> for example, it doesn't work.
The reason why Alert shows up and Fields not is because Fields require addtional props passed by react-admin direct parent, in that case, the Tab. <> should pass such props too, but looks like it's not. And thats why a single <TextField> as child renders correctly
You can create a component that pass the props downstream to childs.
export const ServiceShow = (props) => (
<ShowController {...props}>
{controllerProps =>
<ShowView component="div" {...props} {...controllerProps}>
<TabbedShowLayout>
<Tab label="General">
<Maintenance/>
</Tab>
</TabbedShowLayout>
</ShowView>
}
</ShowController>
);
const Maintenance = props => (
{props.record && props.record.maintenance && props.record.maintenance.active &&
<>
<Alert {...props} severity="warning">Maintenance period active</Alert>
<DateField {...props} label="Maintenance Start" src="maintenance.start" />
<DateField {...props} label="Maintenance End" srvc="maintenance.end" />
<TextField {...props}label="Maintenance Message" source="maintenance.msg" />
</>
}
)

No impact on URL with Material-UI BottomNavigation

I am trying to create a Bottom Navigation bar using material-ui (link:https://material-ui.com/components/bottom-navigation/).
Unfortunately, when I created the component, clicking on each tap did not affect my URL.
Initially, I was using the Link component from React, which allowed me to route between various components. However, as I integrate the Link component into the BottomNavigation component, the style changes and is not working properly anymore.
Here's my current code (without the Link component):
function NavigationAuth() {
const [value, setValue] = React.useState("/");
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<BottomNavigation
value={value}
onChange={handleChange}
showLabels
>
<BottomNavigationAction label="Home" value="/" icon={<HomeIcon />} />
<BottomNavigationAction label="Progress" value="/home" icon={<TimelineIcon />} />
<BottomNavigationAction label="Vote" value="/overview" icon={<ThumbsUpDownIcon />} />
<BottomNavigationAction label="Account" value="/account" icon={<AccountCircleIcon />} />
</BottomNavigation>
);
}
Does anyone have an idea how I can actually change the URL (while using the BottomNavigation component) as a normal Link component would do?
Many thanks in advance!
You can import {useHistory} from react-router-dom and use it to change the URL:
function NavigationAuth() {
const [value, setValue] = React.useState("");
const history = useHistory();
const handleChange = (event, newValue) => {
history.push(`/${newValue}`);
setValue(newValue);
};
return (
<BottomNavigation
value={value}
onChange={handleChange}
showLabels
>
<BottomNavigationAction label="Home" value="" icon={<HomeIcon />} />
<BottomNavigationAction label="Progress" value="progress" icon={<TimelineIcon />} />
<BottomNavigationAction label="Vote" value="overview" icon={<ThumbsUpDownIcon />} />
<BottomNavigationAction label="Account" value="account" icon={<AccountCircleIcon />} />
</BottomNavigation>
);
}
You need both react-router and material-ui to accomplish what you're describing. Material-ui is a UI library and has no intention of providing functionality like routing, only the UI to control routing however you see fit.
Instead of using Link, and assuming this component is wrapped by BrowserRouter at a higher level, change the URL in your handleChange function like this:
const handleChange = (event, newValue) => {
props.history.push(newValue);
};
history is a prop injected by react-router that lets you programmatically update the URL by calling push.
The other way to do this would be the useHistory hook instead of passing it as a prop.

Access current record in admin on rest edit

I need to access the current record in admin on rest Edit. I have an entity and need one of it's properties to do a conditional task. I searched all over the internet and found nothing.
export const UserEdit = (props) => (
<Edit {...props}>
<SimpleForm>
<TextField source="Username" label="Username" />
</SimpleForm>
</Edit>
);
This is not possible with admin-on-rest but this is where React comes to the rescue, you can create a component to add this behaviour.
Something like:
const WithProps = ({children,...props}) => children(props);
And use it like this:
export const UserEdit = (props) => (
<Edit {...props}>
<WithProps>{({record,...props})=>
<SimpleForm record={record} {...props}>
<TextField source="Username" label="Username" />
</SimpleForm>}
</WithProps>
</Edit>
);
Are you looking for aor-dependent-input?
https://github.com/marmelab/aor-dependent-input
It allows to display an input depending on other inputs values. It's authored and supported by the admin-on-rest core team.
Normally you don't have an access to a record inside a SimpleForm.
Perhaps, you can define a custom field and wrap a TextField inside it with access to the record so as to perform a conditional check as desired.
ex:
const CustomTextField = ({record = {}, source}) => (
{ record.foo ? <TextField source="username" label="username" /> : <WhateverField /> }
);
and then, use the CustomTextField in your UserEdit instead.

Resources