Wrapper component for admin-on-rest - reactjs

I would like to create a new component that contains Inputs and Fields from aor and use it in <SimpleForm> and <TabbedForm> as below:
const WrapperComp = () => {
return (
<div>
<TextFieldLabel muiTheme={muiTheme}>Title Example</TextFieldLabel>,
<TextInput source="status"/>,
<TextField source="status"/>
</div>
)
}
<SimpleForm>
<WrapperComp />
</SimpleForm>
but I get Uncaught Error: The TextInput component wasn't called within a redux-form <Field>. Did you decorate it and forget to add the addField prop to your component?.
Any help would be appreciated. Thanks!

You need to use Field from redux-form to decorate your AOR inputs and use TextField from AOR and pass {...props} as pointed by kunal pareek
import React from 'react';
import {
LongTextInput,
ImageField,
ImageInput,
TextField
} from 'admin-on-rest';
import { Field } from 'redux-form';
const CustomGroupComp = (props) => (
<div>
<TextField source="status" {...props} />
<Field name="staffComment" component={LongTextInput} label="staffComment" {...props} />
<Field name="adminComment" component={LongTextInput} label="resources.faults.fields.adminComment" {...props} />
<Field multiple name="fileA" component={ImageInput} accept="image/*">
<ImageField source="path" title="title"/>
</Field>
</div>
);
export default CustomGroupComp;

AOR SimpleForm works by passing the Redux-Form props into its children components. Since you are wrapping up your component, those props aren't passing down to the components you need. You will need to explicitly do this now. So something like
const WrapperComp = (props) => {
return (
<div>
<TextFieldLabel {...props} muiTheme={muiTheme}>Title Example</TextFieldLabel>,
<TextInput {...props} source="status"/>,
<TextField {...props} source="status"/>
</div>
)
}

Related

Prevent Chip component to send a REST request

I have the following code:
import React from 'react';
import PropTypes from 'prop-types';
import Chip from '#material-ui/core/Chip';
import withStyles from '#material-ui/core/styles/withStyles';
const styles = {
root: {
margin: 4,
},
};
function CustomChipField({ root, classes, record, onClick }) {
return (
<Chip className={classes.root} label={`${record.name}`} onClick={onClick} />
);
}
CustomChipField.propTypes = {
classes: PropTypes.shape({}).isRequired,
record: PropTypes.shape({}),
onClick: PropTypes.func.isRequired,
};
CustomChipField.defaultProps = {
record: {},
};
export default withStyles(styles)(CustomChipField);
What is it? It is a custom Chip component inheriting material-ui's chip.
But what I haven't figured out yet is why it sends REST request when I click it.
The example of such a request: http://localhost:3000/#/users/{"name"3A"whatever_name"}
I have an onClick prop overriden, and it was my attempt to override it but it doesn't do anything.
I use this component in the SingleFieldList of react-admin, and maybe the problem in react-admin but I use custom Chip component directly inherited from material-ui.
The code from react-admin:
export const UserList = props => (
<List {...props}>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="username" />
<ArrayField source="some_array">
<SingleFieldList>
<CustomChipField
source="name"
size="small"
clickable={true}
onClick={handleClick}
/>
</SingleFieldList>
</ArrayField>
</Datagrid>
</List>
);
And once again - onClick prop doesn't work.
So the question is: how to whether prevent Chip component sending a REST-request, whether to customize it.
This worked for me:
<SingleFieldList linkType={false}>
<CustomChipField />
</SingleFieldList>

How to use React Hook Form with Typescript (Input Component)

The component has no errors, but in the index file where I actually call the input component, it has an error because it cannot use register = {register}.
What is missing? Or what's wrong?
https://codesandbox.io/s/react-hook-form-typescript-xnb1u
OK here the problems:
you need to add register to props in the Input component props declaration
you must use the register passed as prop, not a new one created with useForm in Input component
the input element is missing the name attribute
here the working <Input> component with comments:
import React, { InputHTMLAttributes } from "react";
import {
FieldValues,
UseFormRegister,
// useForm, // don't need this import
} from "react-hook-form";
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
id: string;
label: string;
register: UseFormRegister<FieldValues>; // declare register props
}
const Input: React.FC<InputProps> = ({ id, label, register, ...rest }) => {
//const { register } = useForm(); // don't use a new `register`, use the one from props
return (
<div className="input-block">
<label htmlFor={id}>{label}</label>
<br />
<br />
{/* react-hook-form v6 */}
{/* you must declare the `name` attribute on the input element */}
<input name={id} type="text" id={id} ref={register} {...rest} />
{/* react-hook-form v7 */}
{/* In v7 the register() function returns all the needed properties */}
{/* see: https://dev.to/bluebill1049/what-s-coming-in-react-hook-form-version-7-4bfa */}
{/* <input type="text" id={id} {...register(id)} {...rest} /> */}
</div>
);
};
export default Input;
I found an article that helped me find the solution.
Codebox has the right solution for those who want to use typescript componentization using React Hook Form.
https://codesandbox.io/s/react-hook-form-typescript-xnb1u

React-admin SimpleForm does not call PUT request when click save

In react-admin, SimpleForm should automatically call PUT request, however it does not work. Instead, for some odd reason, it's calling GET request whenever I click the save button. I'm new to react-admin and I've been looking around for solutions but I have no idea what's wrong. I have tried calling PUT request with postman and it works, so I know for sure that my backend is not the problem.
import React from 'react';
import { Provider } from 'react-redux';
import { createHashHistory } from 'history';
import simpleRestProvider from 'ra-data-simple-rest';
import createAdminStore from '../createAdminStore';
import { Admin, Resource } from 'react-admin';
import {
CategoryList,
CategoryShow,
ItemList,
ItemShow,
ItemEdit
} from '../adminComponents/posts';
const dataProvider = simpleRestProvider('http://localhost:3000/api');
const history = createHashHistory();
const AdminContainer = () => (
<Provider store={createAdminStore({dataProvider, history })}>
<Admin dataProvider={dataProvider} history={history} title="My Admin">
<Resource name="categories" list={CategoryList} show={CategoryShow} />
<Resource name="items" list={ItemList} show={ItemShow} edit={ItemEdit}/>
</Admin>
</Provider>
);
Here's Item Edit component:
export const ItemEdit = props => (
<Edit {...props} >
<SimpleForm>
<TextInput disabled source="id" />
<TextInput source="name" />
<TextInput source="description" />
<NumberInput source="price" />
{/* <TextInput source="selections" /> */}
<ReferenceInput source="category_id" reference="categories">
<SelectInput optionText="name" />
</ReferenceInput>
</SimpleForm>
</Edit>
);
It might not be related, but I just resolved this issue using react-admin 3.7. I've got an Edit component wrapping a SimpleForm, and when I removed the onSuccess attribute, the form started working again.

pass onChange func props doesn't work material-ui-picker react

It is necessary to pass from the child component of the props it is a change, but the validation of the piker disappeared and the state does not change
My Stateless Component
import { KeyboardDatePicker } from "#material-ui/pickers";
import MomentUtils from "#date-io/moment";
import { MuiPickersUtilsProvider } from "#material-ui/pickers";
const Picker = ({dateOnChange,dateOfOrdinance}) => {
<MuiPickersUtilsProvider utils={MomentUtils}>
<KeyboardDatePicker
inputVariant="outlined"
clearable
label="От:"
value={dateOfOrdinance}
onChange={dateOnChange}
format="YYYY-MM-DD"
InputAdornmentProps={{ position: "start" }}
/>
</MuiPickersUtilsProvider>
}
My parent Component
export default class Case extends Component {
state={dateOfOrdinance: new Date()}
render() {
return (
<Picker dateOnChange={(date)=>
this.setState({dateOfOrdinance: date}) />
)
}
}
If I declare it in the parent, then everything will be fine, there will be validation and the state will change
There is problems in this line,
<Picker dateOnChange={(date)=> this.setState({dateOfOrdinance: date}) />
You have not passed dateOfOrdinance as props here, do this to pass data
<Picker dateOfOrdinance={this.state.dateOfOrdinance} dateOnChange={(date)=> this.setState({dateOfOrdinance: date}) />

Custom layout in SimpleForm component on react-admin

I want to create a custom two-column-grid layout on my react-admin project on Edit and Show pages. I want to display selectboxes and the imageupload area on the left column, and the text inputs on the right column by using only one <SimpleForm>.
Simply like this
If I use a div or a <Card> component under <SimpleForm> and <EditController> components, I receive an error.
Warning: React does not recognize the `basePath` prop on a DOM element.
If you intentionally want it to appear in the DOM as a custom
attribute, spell it as lowercase `basepath` instead. If you
accidentally passed it from a parent component, remove it from the DOM
element.
Is there any way to create a layout without this error?
I solved it with creating another component with using divs, <Grid/> etc, and used that component in <SimpleForm> component.
import {withStyles} from '#material-ui/core/styles';
import React from 'react';
import {
EditController,
SimpleForm,
TextInput,
SelectInput,
Title,
} from 'react-admin';
import Grid from '#material-ui/core/Grid';
import Card from '#material-ui/core/Card';
import Poster from "../customField/Poster";
import {EditToolbar} from '../toolbar/CustomToolbar'
import {EditActions} from '../toolbar/CustomActions'
const editStyles = {
root: {display: 'flex', alignItems: 'flex-start', width: '100%'},
form: {flexGrow: 9},
};
class CardEdit extends React.Component {
constructor(props) {
super(props);
this.state = {
refresh: false
};
}
render() {
const FormDiv = withStyles(editStyles)(({children, classes, ...props}) => {
return (
<div className={classes.root}>
<div className={classes.form}>
<Grid container spacing={24}>
<Grid item xs={6}>
<TextInput source="name" fullWidth />
</Grid>
<Grid item xs={6}>
<TextInput source="card_id" fullWidth />
</Grid>
</Grid>
</div>
</div>
)
}
)
return (
<EditController {...this.props}>
{({resource, record, redirect, save, basePath, version}) => {
return (
<div>
<Title defaultTitle="sample"/>
<Card>
<div style={{ margin: '20px 20px 0 0' }}>
<EditActions
basePath={basePath}
resource={resource}
data={record}
hasShow
hasList
/>
</div>
{record && (
<SimpleForm
basePath={basePath}
redirect={redirect}
resource={resource}
record={record}
save={save}
version={version}
toolbar={<EditToolbar/>}
>
<FormDiv record={record} />
</SimpleForm>
)}
</Card>
</div>
)
}}
</EditController>
)
}
}
export default withStyles(editStyles)(CardEdit);
Actually, this could be done a little bit easier in case you don't need any custom styles and what not.
In order to get rid of the basePath error, just sanitize the props passed to the Material UI Grid Component:
const SanitizedGrid = ({basePath, ...props}) => {
return (
<Grid {...props} />
);
};
Then use it in place of a normal Grid:
export default props => (
<SimpleForm {...props}>
<SanitizedGrid container spacing={16}>
<Grid item xs>
<TextInput source="name" />
</Grid>
</SanitizedGrid>
</SimpleForm>
);
As another way, I've just worked out (thanks to Alexander's answer) a nice generic way to add any custom HTML content to a react-admin form:
import React, { Fragment } from 'react';
import { SimpleForm } from 'react-admin';
const CustomContent = ({ basePath, record, resource, children }) => (
<Fragment>
{children}
</Fragment>
);
export const MyForm = (props) => (
<SimpleForm>
<CustomContent>
<h3>Custom Content</h3>
<p>I can now add standard HTML to my react admin forms!</p>
</customContent>
</SimpleForm>
);
You get the basePath prop (which you probably don't want), but the record and resource props might be useful to your custom content (if you switch the code to use a render prop)

Resources