React-Admin linking two fields - react-admin

I am trying to use React-Admin tutorial covering how to link to inputs without success.
I have a API endpoint that has users and each user has multiple accounts. I want to create an Edit/Create form where you can choose a user then from next field dropdown to have possibility to select an account that user has (values can be 0, 1, ..n accounts).
<SimpleForm toolbar={<MyToolbar />}>
<ReferenceInput label="User Name:" source="Id" reference="users" {...rest}>
<AutocompleteInput optionText="User.name" {...rest}/>
</ReferenceInput>
<FormDataConsumer>
{({ formData, ...rest }) => (
<SelectInput
source="users"
optionText="Account"
choices={
formData.user.Id
}
{...rest}
/>
)}
</FormDataConsumer>
</SimpleForm>

Actually it works just like in react-admin documentation; problem was in my custom API as I did not implement all filters, options etc on getList type of calls.

Related

Activating text search filtering

I'm learning react admin and I have a simple page w/some filters like so:
import * as React from "react";
import { List, TextField, Datagrid, TextInput } from 'react-admin';
import { PostPaginationm } from "./MyPagination";
const postFilters = [
<TextInput label='Field' source="_Field-Name_matches" alwayson alwaysOn />,
<TextInput label='Index' source="_Index-Name" alwaysOn />,
<TextInput label='File' source="_File-Name" alwaysOn />,
<TextInput label='Db' source="_db-name" alwaysOn />,
];
export const IndexFieldSchemaList = () => (
<List filters={postFilters} pagination={<PostPaginationm/>}>
<Datagrid>
<TextField source="id" label="Id"/>
<TextField source="_db-name" label="Db"/>
<TextField source="_File-Name" label="File"/>
<TextField source="_Index-Seq" label="Seq"/>
<TextField source="_Index-Name" label="Index"/>
<TextField source="_Field-Name" label="Field"/>
<TextField source="_Ascending" label="Asc"/>
<TextField source="_Abbreviate" label="Abbr"/>
</Datagrid>
</List>
);
When I fill in one of the filters I get the following GET action:
GET http://localhost:12537/React/web/table/indexfieldschema?filter={"_File-Name":"extent"}&range=[0,49]&sort=["id","ASC"]
Previously I'd get something like this where the "q" field was added to the filter:
GET http://localhost:12537/React/web/table/indexfieldschema?filter={"q": "e", "_File-Name":"extent"}&range=[0,49]&sort=["id","ASC"]
I've coded the API to work with the "q" specification - w/out that it does a straight equality match which doesn't filter records the way I want.
How do I get the "q" field added to the filter the way I need? I'd note that when I originally coded this it added the "q" field so I'm not sure what changed to stop that behavior.
As it turns out the 'q' spec didn't work the way I thought it did and didn't give me the functionality I was after so the answer is how I got what I wanted.
You have to name your input "q":
const postFilters = [
<TextInput label="Search" source="q" alwaysOn />
];
What I ended up doing is taking advantage of the ability to add a "matches" query condition to a field which my backend'll use to do the search I want for each field.
const postFilters = [
<TextInput label='Field' source="_Field-Name_matches" alwayson alwaysOn />,
<TextInput label='Index' source="_Index-Name_matches" alwayson alwaysOn />,
<TextInput label='File' source="_File-Name" alwayson alwaysOn/>,
<TextInput label='Db' source="_db-name" alwayson alwaysOn/>
];

get the roles previously linked to users

i have a problem i cannot solve, and i think im following the documentation to the letter.
I want to obtain the assigned roles when im editing the user, for example if exist a user "Daniel", which has "Administrator" and "Editor" roles. When im editing that user i would like to obtain those assigned roles.
my code is:
export const UserEdit = props => (
<Edit title={<RoleTitle />} {...props}>
<SimpleForm validate={validateUserEdition}>
<TextInput source="name" />
<TextInput source="email" type="email" />
<TextInput source="password" type="password" />
<ReferenceInput label="Role" source="role" reference="role">
<AutocompleteArrayInput source="id" {...props} />
</ReferenceInput>
</SimpleForm>
</Edit>
);
Add the endpoint format where check my API:
GET to /user/{user}/role
someone help me with this please?
Here's what the react-admin say:
You must add a for the reference resource - react-admin needs it to fetch the reference data.
So in your case, the <Admin/> component should at least have these:
<Admin dataProvider={myDataProvider}>
<Resource name="users" /> // endpoint that handles user records
<Resource name="roles" /> // endpoint that handles user ROLES records
</Admin>
Am not sure how you are using this endpoint /user/{user}/role but it clearly will not do what you want. Further reading here should help especially look at the notes added to the Reference* components.
I still cannot solve my problem, the resources that I have in my administrator are user and role, but I imagine that with those resources they are enough to have the relationship between the two.
Again, when I edit a user, I need to be able to view and edit the roles associated with it.
my code is the follow
export const UserEdit = props => (
<Edit title={<RoleTitle />} {...props}>
<SimpleForm validate={validateUserEdition}>
<TextInput source="name" />
<TextInput source="email" type="email" />
<TextInput source="password" type="password" />
<ReferenceInput label="Role" source="role" reference="role">
<AutocompleteArrayInput source="id" {...props} />
</ReferenceInput>
</SimpleForm>
</Edit>
);
in app.js
const App = ( ) => (
<Admin dashboard={ Dashboard } dataProvider={ dataProvider } authProvider={ authProvider }>
<Resource name="user" list={ UserList } create={ UserCreate } edit={ UserEdit } icon={ UserIcon }/>
<Resource name="role" list={ RoleList } create={ RoleCreate } edit={ RoleEdit } icon={ ContactsIcon }/>
</Admin>
);
Thank

Display Field in Edit Form

Currently, if I try to place a Field into an Edit form, the field doesn't display at all. There is no errors in the console or the terminal about why it wont.
Example:
<Edit undoable={false} {...props}>
<SimpleForm>
<FormRow>
<TextField source="id"/>
<TextField source="name"/>
</FormRow>
</SimpleForm>
</Edit>
will not display either of these on the page load, it will simply be blank.
Is there any way to use fields in the Edit form?
You need to pass in the record prop (and basePath if its a reference).
The Edit component does not get the record prop so create a form component and it will get passed the record as a prop
eg.
const ProjectEdit: FC<EditComponentProps> = props => {
const classes = useStyles();
return (
<RA.Edit {...props} title={<ProjectTitle />}>
<RA.SimpleForm>
<ProjectForm />
</RA.SimpleForm>
</RA.Edit>
);
};
export const ProjectForm = (props: any) => {
return (
<Box flex={1} mr={{ md: 0, lg: '1em' }}>
<RA.TextInput source="name" fullWidth={true} />
<Typography variant="h6" gutterBottom>
Tasks
</Typography>
<RA.TextField
source="name"
fullWidth={true}
record={props.record}
/>
<RA.ReferenceManyField
label="Tasks"
reference="Task"
target="projectId"
fullWidth={true}
record={props.record}
basePath="/Task"
>
<RA.SingleFieldList fullWidth={true}>
<RA.ChipField source="name" fullWidth={true} />
</RA.SingleFieldList>
</RA.ReferenceManyField>
</Box>
);
};

ShowController with TabbedShowLayout

I am actually doing a dashboard using React-Admin, and I discovered the <ShowController> who permits to use Material-UI components inside the Show View.
But my problem comes here, I used a <TabbedShowLayout> and it doesn't work really well. Let me explain :
<ShowController {...props}>
{controllerProps =>
<ShowView {...props} {...controllerProps}>
<TabbedShowLayout {...controllerProps}>
<Tab icon={<AssignIcon />}>
<div>
<TextField source="id" />
</div>
</Tab>
</TabbedShowLayout>
</ShowView>
}
</ShowController>
Here is my actual code, and it displays nothing except the tab with the icon.
But if i remove the <div> component, it works.
I would like to know, if someone ever does that, and made it works.
Thanks by advance
The reason is properties inheritance is not "native", you have to do it manually. react-admin is doing it in each component.
When you insert a div element in a react-admin form or layout, you break this inheritance between Tab and TextField. The div is receiving props from parent Tab, but doesn't forward them to TextField.
One solution is to make a custom wrapper. In your case:
<ShowController {...props}>
{controllerProps =>
<ShowView {...props} {...controllerProps}>
<TabbedShowLayout {...controllerProps}>
<Tab icon={<AssignIcon />}>
<CustomDiv>
<TextField source="id" />
</CusomDiv>
</Tab>
</TabbedShowLayout>
</ShowView>
}
</ShowController>
With
const CustomDiv = ({children, ...props}) => (
<div>
{
React.Children.map(children, child => React.cloneElement(child, {...props, ...child.props}))
}
</div>
);

Unable to reset all the choices in SelectInput

The user needs to select a project in the AutocompleteInput first, doing that will set the filter property on the ReferenceInput which will load the possible values from the server into the SelectInput choices list. The data is fetched from the server however, if the choice that was selected in the SelectInput is no longer in the list, it is not reset. Furthermore the selected value is still in the choices list even though it was not returned from the rest service.
This is the code i wrote that has this issue:
<ReferenceInput label="Project" source="projectId" reference="projecten" filterToQuery={searchText => ({ naam: searchText })}>
<AutocompleteInput optionText="naam" optionValue="id" inputValueMatcher={() => null} />
</ReferenceInput>
<FormDataConsumer>
{({ formData, ...rest }) => {
return <ReferenceInput label="Lot" source="lotId" reference="loten" filter={{ projectId: formData.projectId }} {...rest}>
<SelectInput optionText="lotNummer"/>
</ReferenceInput>
}}
</FormDataConsumer>
How do I reset the SelectInput onChange of the AutocompleteInput and not load the currently selected value?
I know it's a late reply, but it might help someone. I achieved the same effect by using following steps on two SelectInputs inside a ReferenceInput each. I hope it works for your structure as well.
import change from redux-form
import { change } from redux-form
Give your SimpleForm a name
<SimpleForm form="myForm"...
Move your first ReferenceInput inside the FormDataConsumer
<FormDataConsumer>
{({ formData, ...rest }) => {
return (
<div>
<ReferenceInput label="Project" ...
<ReferenceInput label="Lot" ...
</div>
);
}
</FormDataConsumer>
Add an onChange to your first ReferenceInput
<ReferenceInput
label="Project" source="projectId" reference="projecten"
filterToQuery={searchText => ({ naam: searchText })}
onChange={() => {rest.dispatch(change('myForm', 'lotId', ''))}} >
Add a key property to your second ReferenceInput and use your first ReferenceInput's source as it's value
<ReferenceInput label="Lot" source="lotId"
reference="loten" filter={{ projectId: formData.projectId }}
key={formData.projectId} {...rest}>
Finally you'll get
<SimpleForm name="myForm">
<FormDataConsumer>
{({ formData, ...rest }) => {
return (
<div>
<ReferenceInput label="Project" source="projectId"
reference="projecten"
filterToQuery={searchText => ({ naam: searchText })}
onChange={() => {rest.dispatch(change('myForm', 'lotId', ''))}} >
<AutocompleteInput optionText="naam" optionValue="id"
inputValueMatcher={() => null} />
</ReferenceInput>
<ReferenceInput label="Lot" source="lotId" reference="loten"
filter={{ projectId: formData.projectId }}
key={formData.projectId} {...rest} >
<SelectInput optionText="lotNummer" />
</ReferenceInput>
</div>
);
}}
</FormDataConsumer>
</SimpleForm>
I used the steps from this link and added the key property according to another SO question but I'm unable to find it now.