How to change variant of text input in react admin - reactjs

I wanted to change the variant of TextInput using material UI. The default variant is Standard and I want to change that to outlined but not able to do so. Followed documentation for material-ui Material-ui documentation
Below is my code snippet
<TabbedForm>
<FormTab label="INFO">
{/* <TextInput disabled label="" source="id" type="hidden"/> */}
<TextInput label="Name" source="name" variant="outlined"/>
<TextInput source="shortdesc" />
</FormTab>
</TabbedForm>

You need to pass in variant="standard" to the react-admin <TextInput> component. The issue is that the <Filter> and <Create> pages, etc, automatically pass in a bunch of props, like record and basePath, which includes variant: undefined for some reason. So if you just write <TextInput variant="standard" ... />, your prop will get overwritten. And then when the TextInput component passes its props to the ResettableTextField component, the now undefined variant prop gets defaulted to "filled"...
So, you just need to extract the TextInput component out, so that your variant prop comes last in the props order:
export const TextInput = props => <RaTextInput {...props} variant="standard" />
Personally, I've abstracted this all out into a HOC, because this is what you have to do for all the Inputs that use TextFields:
import React from 'react'
import {
TextInput as RaTextInput,
NumberInput as RaNumberInput,
SelectInput as RaSelectInput,
DateInput as RaDateInput,
DateTimeInput as RaDateTimeInput,
NullableBooleanInput as RaNullableBooleanInput,
AutocompleteInput as RaAutocompleteInput,
} from 'react-admin'
const standardize = Component => props => <Component {...props} variant="standard" />
export const TextInput = standardize(RaTextInput)
export const NumberInput = standardize(RaNumberInput)
export const SelectInput = standardize(RaSelectInput)
export const DateInput = standardize(RaDateInput)
export const DateTimeInput = standardize(RaDateTimeInput)
export const NullableBooleanInput = standardize(RaNullableBooleanInput)
export const AutocompleteInput = standardize(RaAutocompleteInput)

Check my code
<TabbedForm>
<FormTab label="INFO">
{/* <TextInput disabled label="" source="id" type="hidden"/> */}
<TextField label="Name" source="name" variant="outlined"/>
<TextField source="shortdesc" />
</FormTab>
</TabbedForm>
check my fork

React-admin has fixed this.
You can now use the variant="outlined | standard | filled" prop on the component enclosing the input.
Ex: SimpleForm, Create, Filter, etc.
The Git resolution

Related

How to change Material UI component property according to props

This is my react js code with MUI TextField and I need to apply error and helperText property when error prop has a value. default error prop value is null.
import React from 'react'
import { TextField } from '#mui/material'
const InputField = (props) => {
const { name, label, value,error=null, onChange } = props;
return (
<TextField
variant='outlined'
label={label}
name={name}
value={value}
onChange={onChange}
{...{error && {error:true,helperText:error}}}
/>
)
}
export default InputField
The error is on this line. How I figer it on MUI 5.10.9 version
{...{error && {error:true,helperText:error}}}
use error and helperText prop directly without condition. also use space character inside helperText to avoid height issue when there is no error present. https://mui.com/material-ui/react-text-field/#helper-text
<TextField
variant='outlined'
label={label}
name={name}
value={value}
onChange={onChange}
error={!!error}
helperText={error || ' '}
/>

Capture onChange event from inputComponent passed to OutlinedInput, Material UI

I'm trying to use OutlinedInput with KeyboardDatePicker, both from Material UI. I'm passing a DatePicker as input component to 'OutlinedInput' component of Material UI. I want to know how to get date from the inputComponent I'm passing.
With the following code I'm getting "_onChange is not a function" error.
const handleInputChange = (event) => {
if (event.target.name === "deliveryDate") {
temp.deliveryDate = event.target.value;
}
}
function datepicker() {
return <MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
name="deliveryDate"
format="MM/dd/yyyy"
value={projectDetails.deliveryDate}
onChange={props.handleInputChange} /> //not sure if this is how I should write it
</MuiPickersUtilsProvider>;
}
return(
<OutlinedTextBox
name="deliveryDate"
id="deliveryDate"
maxlength={20}
onChange={handleInputChange}
inputComponent = {datepicker} //passing the KeyboardDatePicker as input component
inputLabel="Delivery Date" />
)
Below is my OutlinedTextBox component. It returns
<OutlinedInput
name={props.name}
inputProps={{
maxLength: props.maxlength?props.maxlength:100,
}}
onChange={props.handleInputChange}
{...props}
/>
How to capture onChange function of inputComponent attribute.
Update
From what you said in your comment, all you actually have to do then is edit your datepicker component. You dont need to pass in the value, onChange or name directly as those are already being passed in as props from when you use inputComponent={datepicker}. So all you need to do is declare the props and spread them all into the KeyboardDatePicker.
const DatePicker = (props) => {
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
format="MM/dd/yyyy"
{...props}
/>
</MuiPickersUtilsProvider>
);
};
Original Answer.
You could just add the inputVariant="outlined"property to the KeyboardDatePicker as that will make it outlined. Then you dont actually need to use the OutlinedInput component at all.
<KeyboardDatePicker
name="deliveryDate"
format="MM/dd/yyyy"
value={projectDetails.deliveryDate}
onChange={props.handleInputChange}
inputVariant="outlined
/>

React-admin: ReferenceInput doesn't show loading <LinearProgress> while loading possible options

I have simple react-admin edit form with ReferenceInput. The problem is that ReferenceInput never show progress bar, so it might be confusing for users to see no options while it's loading.
I manually set delay 2 seconds on API calls but ReferenceInput never show loading state.
import React from 'react';
import { ReferenceInput, ReferenceArrayInput, required, SelectArrayInput, SelectInput, SimpleForm, TextInput } from 'react-admin';
const ModelForm = props => (
<SimpleForm {...props}>
<TextInput source="name" validate={[required()]} />
<ReferenceInput reference="goods_types" source="goodsType" validate={[required()]}>
<SelectInput optionText="name" />
</ReferenceInput>
<ReferenceInput reference="manufacturers" source="manufacturer" validate={[required()]}>
<SelectInput optionText="name" />
</ReferenceInput>
<ReferenceArrayInput reference="manufacturers" source="manufacturer" format={v => [v]} validate={[required()]}>
<SelectArrayInput optionText="name" />
</ReferenceArrayInput>
</SimpleForm>
);
export default ModelForm;
Just for test I added ReferenceArrayInput component and it does show loading progress bar.
Is it bug in react-admin? Or am I missing something?
React-admin: 3.11.1
React Admin introduced a timeout with default value of 1000. The loading component only appear after this time. You can override this value by passing a prop to the component.
ref: https://github.com/marmelab/react-admin/blob/ea1f85c73f5be8f12544a0fccf32e4f6bd7452be/packages/ra-ui-materialui/src/layout/LinearProgress.tsx

React Admin - overiding handleSubmit on SimpleForm

What I want to achieve is this but using react admin SimpleForm instead of Form:
import React, { useState } from "react";
export function NameForm(props) {
const [name, setName] = useState("");
const handleSubmit = (evt) => {
evt.preventDefault();
alert(`Submitting Name ${name}`)
}
return (
<form onSubmit={handleSubmit}>
<label>
Frirst Name:
<input
type="text"
value={name}
onChange={e => setName(e.target.value)}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
When I try the same pattern, i.e.:
<SimpleForm onSubmit={handleSubmit}>
it never reaches the handleSubmit function. I also tried:
<SimpleForm handleSubmit={handleSubmit}>
But again no joy.
The react admin docs here say:
Finally, it receives a handleSubmit function as prop, to be called with the updated record as an argument when the user submits the form.
Unfortunately being new to react this doesn't give me any clue as to what I should do to get this to work.
When you're using any third party library you need to follow their rules. Here you're using React admin library which support normal admin features like add/edit/listing etc. With minimal effort you can create admin panel.
So when you're focusing on creating form using React Admin , you can create add/edit form.
In your App.js you need to first define routing using Resource which contains create and edit attribute. In create/edit you can import your add/edit component and pass it. The example is given below. You can see dataProvider link is also provided. When you'll create edit form it will take data from there
// in src/App.js
import * as React from "react";
import { Admin, Resource } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
import { PostCreate, PostEdit } from './posts';
const App = () => (
<Admin dataProvider={jsonServerProvider('https://jsonplaceholder.typicode.com')}>
<Resource name="posts" create={PostCreate} edit={PostEdit} />
</Admin>
);
export default App;
After creating proper routing you can go to your component and can create add/edit form just like below
// in src/posts.js
import * as React from "react";
import { Create, Edit, SimpleForm, TextInput, DateInput, ReferenceManyField, Datagrid, TextField, DateField, EditButton } from 'react-admin';
import RichTextInput from 'ra-input-rich-text';
export const PostCreate = (props) => (
<Create {...props}>
<SimpleForm>
<TextInput source="title" />
<TextInput source="teaser" options={{ multiLine: true }} />
<RichTextInput source="body" />
<DateInput label="Publication date" source="published_at" defaultValue={new Date()} />
</SimpleForm>
</Create>
);
export const PostEdit = (props) => (
<Edit {...props}>
<SimpleForm>
<TextInput disabled label="Id" source="id" />
<TextInput source="title" validate={required()} />
<TextInput multiline source="teaser" validate={required()} />
<RichTextInput source="body" validate={required()} />
<DateInput label="Publication date" source="published_at" />
<ReferenceManyField label="Comments" reference="comments" target="post_id">
<Datagrid>
<TextField source="body" />
<DateField source="created_at" />
<EditButton />
</Datagrid>
</ReferenceManyField>
</SimpleForm>
</Edit>
);
React-admin injects a few props to the create and edit views: the resource name, the basePath (the root URL), the permissions, and, in the case of the edit view, the record id. That’s why you need to pass the props to the <Create> and <Edit> components.
The <Create> and <Edit> components call the dataProvider, prepare the form submit handler, and render the page title and actions.
<SimpleForm> Which you mentioned in your question is responsible for creating the form only, it's not responsible for handleSubmit operation , <Create> and <Edit> components handle that.
To know more in details follow the React Admin <Create> and <Edit> doc carefully.
So I found the solution I was looking for thanks to the answer from Saswata Pal. To achieve the effect I was looking for I changed the component so it was like this:
<Create transform={transform}>
This allowed me to grab the form result before submission and modify.
Relevant docs here:
https://marmelab.com/blog/2020/06/09/react-admin-3-6.html

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