Access current record in admin on rest edit - reactjs

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.

Related

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

react-bootstrap how to use custom form control component

I need to add select input in my form, but there are too many options, so the default way to do it looks really ugly(
<Form.Control as="select">
{props.options.map(
(o) => <option>{o}</option>
)}
</Form.Control>
So I've decided to use react-bootstrap-typeahead because it's already being used in my project and it supports search. However, it didn't work properly in that case.
<Form>
<Form.Group>
<Form.Label>Provider</Form.Label>
<Form.Control
as={Typeahead}
id="id"
options={props.options}
/>
</Form.Group>
</Form>
It looks like this:
Might I've done it not properly, but I can't figure out how to do it in another way(
https://react-bootstrap.github.io/components/forms/#form-control-props
Ther has a props "as". See exemle bellow.
export default function Input(props) {
const CustomFormControl = React.forwardRef(({ children, onChange}, ref) => (
<>
<p>Insert your elements for yout form</p>
<p>{props.test}</p>
</>
));
return (
<>
<Form.Control
as = {CustomFormControl}
test = {"hellow world"}
/** and here u can inser the props you need **/
/>
</>
}

How to change variant of text input in react admin

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

Using the Controller components, what is needed to show the Label in the TextFields?

Using React-admin, I am using the ShowController component, which gives me more freedom to customize the ShowView. However, I would like to keep seeing the labels in the TextFields, but, they are gone.
This piece of code shows how I am using the ShowController and, it works partially: only show the record values, not the labels (I also tried without the prop "label", it doesn't work neither).
const OrderShow = props => {
return (<ShowController {...props}>
{controllerProps => {
return (
<Grid container spacing={8}>
<Grid item xs={3}>
<TextField label="ID" source="id" {...controllerProps} />
...
What is missing to show the labels as in the ShowView standard component?
TextFields' labels are usually filled by their source property.
If you want to use <ShowController> component with custom layout, I suggest you to create another custom component and use it inside of <Show>, <ShowView> or <SimpleShowLayout>.
I wrapped the fields with SimpleForm component to be able to show their labels and hide the Toolbar with custom CardActions.
Example:
const FormToolbar = () => (
<CardActions style={{display: 'none'}}>
</CardActions>
);
const FormDiv = ({controllerProps, ...props}) => (
<Grid container spacing={24}>
<Grid item xs={12}>
<SimpleForm toolbar={<FormToolbar/>}>
<TextField {...props} record={controllerProps.record} source="name"/>
</SimpleForm>
</Grid>
</Grid>
);
const OrderShow = props => (
<ShowController {...props} title="Order">
{controllerProps =>
<Show actions={<ShowActions pageType="show" />} {...props} {...controllerProps}>
<SimpleShowLayout>
<FormDiv controllerProps={controllerProps} />
</SimpleShowLayout>
</Show>
}
</ShowController>
);
export default OrderShow;

Is it possible to disable default sorting in React Admin?

I have simple question
Is it possible to disable default sorting by column id? Or at least change it globally?
Thanks for answer
EDIT:
To be more specific, I have REST API (OData) which returns "Id" instead of "id" so I have to set sort everytime I use related component to prevent undefined errors.
I would welcome option to disable default sort in related components.
If you are looking for a solution to disable sort option for that column, you can use sortable={false}.
Example usage:
import React from 'react';
import { List, Datagrid, TextField } from 'react-admin';
export const PostList = (props) => (
<List {...props}>
<Datagrid>
<TextField source="id" sortable={false} />
<TextField source="title" />
<TextField source="body" />
</Datagrid>
</List>
);
Or you can specify a default sort for the List.
export const PostList = (props) => (
<List {...props} sort={{ field: 'published_at', order: 'DESC' }}>
...
</List>
);

Resources