I have a TabbedForm with 2 tabs, each tab having a single required() field. When I submit this form and the validation fails, I expect the unfocussed tab(s) to indicate that there is an error with a field within the tab (e.g. with a red underline or red text).
This appears to be working fine in a react-admin demo (https://marmelab.com/react-admin-demo/#/products/126) however even after looking a the source code for this example (https://github.com/marmelab/react-admin/blob/master/examples/demo/src/products/ProductEdit.tsx), I cannot seem to replicate the same functionality in my project.
I have the following code:
const App = () => {
const dataProvider = jsonServerProvider(
"https://jsonplaceholder.typicode.com"
);
return (
<Admin dataProvider={dataProvider}>
<Resource name="users" list={ListGuesser} edit={EditForm} />
</Admin>
);
};
export const EditForm = (props: EditProps) => {
return (
<Edit {...props}>
<TabbedForm>
<FormTab label="Tab 1">
<TextInput source="name" validate={required()} />
</FormTab>
<FormTab label="Tab 2">
<TextInput source="username" validate={required()} />
</FormTab>
</TabbedForm>
</Edit>
);
};
Image showing Tab 2 selected and is valid and there is a validation error on Tab 1, but no highlight on Tab 1 to tell the user that this is the Tab that has the error.
There has been a similar question asked here (Show Tab Form Validation For Inputs Not Direct Children Of <FormTab>) but the resolution does not apply to my problem.
Is there something I'm missing here?
plz check the demo source code: https://github.com/marmelab/react-admin/blob/master/examples/demo/src/products/ProductEdit.tsx, it's using validate function:
<RichTextInput source="description" label="" validate={req} />
and the "req" is defined at line 86:
const req = [required()];
I've encountered same problem, and solve it by using the way (validation function) of demo source code. HTH
Related
So I'm using the ra-data-json-server as a data provider and the bult in <SimpleForm> component as a form for the <Edit> view, and I'm facing a pretty strange issue, as it says in documentation, when submitted, the <SimpleForm> forces data provider to make a PUT request to the API, but in my case it does not.
Here's my Edit view compnent:
export const UserEdit = props => {
return (
<Edit {...props}>
<SimpleForm>
<ArrayInput source="applications">
<SimpleFormIterator source="applications">
{/* some inputs */}
</SimpleFormIterator>
</ArrayInput>
</SimpleForm>
</Edit>
);
};
And the admin component itself:
export const AdminComp = () => {
return (
<Admin
loginPage={CustomLoginPage}
authProvider={authProvider}
locale="ru"
i18nProvider={i18nProvider}
dataProvider={dataProvider}
>
<Resource
name="students"
list={UserList}
edit={UserEdit}
/>
</Admin>
);
};
And everytime I get into the Edit view and hit the save button it just doesn't do anything.
I managed to make it at least call the update in data provider, but it would call it with the old form data even though it was modified already.
I also tried reinstalling react-admin to the latest version which is what some people reccomended but it didn't help.
when i custom my Create page using ,the can not display correctly. how to fix it?
you can see the following reproduce in code-sandbox.
Visit here
enter the tags list
click the create button, enter to the Create page.
see the input of post.
<Create title=" " {...props}>
<SimpleForm toolbar={<TagCreateToolbar onCancel={onCancel}
/>}>
<TextInput source="name" validate={required()} />
<ReferenceInput label="Post" source="post_id" reference="posts">
<AutocompleteInput optionText="title" />
</ReferenceInput>
</SimpleForm>
</Create>
You need to fix the file: src/tags/index.js as follows:
import TagList from './TagList';
import TagCreate from './TagCreate';
import TagEdit from './TagEdit';
export default {
list: TagList,
create: TagCreate,
edit: TagEdit
};
It's still worth updating react-admin before the last release of 2.9.6
I have a tabbed form that the second tab will retrieve a list from the backend, similar to the react-admin official demo (e.g. post has many comments). The problem is when I switch the tab, there is always a backend call for the second tab which is comment list.
How can I avoid it and just load one time?
Because I have pagination on the second tab, if I switch tab, the pagination will be changed to the first page.
Thank you in advance!
<TabbedForm>
<FormTab label="Post">
<TextInput source="name"/>
</FormTab>
<FormTab label="Comment">
{/* This tab should fetch data only once if I switch tabs */}
<ReferenceManyField
pagination={<Pagination/>}
reference="comments"
target="id"
perPage={5}
addLabel={false}
>
<Datagrid>
<TextField source="name" />
<EditButton />
<DeleteButton undoable={false}/>
</Datagrid>
</ReferenceManyField>
</FormTab>
</TabbedForm>
If you are using Hooks, you could use a combination of useState and useEffect.
useState would hold the result of your data-fetching, which you would trigger in useEffect. To make that happen just once, use an empty array as dependency-array in useEffect:
const [data, setData] = useState(null)
useEffect(() => {
setData(fetchData())
}, [])
<Dialog.Container visible={this.state.dialogSendEmailVisible}>
<Dialog.Title>Password Recovery</Dialog.Title>
<Dialog.Input label="Email"></Dialog.Input>
<Dialog.Button label="OK" onPress={this.handleSendEmail} />
</Dialog.Container>
I have this simple dialog, this is being used for password recovery purposes. I am not a FE developer, and I am not finding how can I pass the value typed on Email field to handleSendEmail function. Github and npm pages do not have any example.
Github page: https://github.com/mmazzarolo/react-native-dialog
PS: This can be a very react native basic feature, but I am not findindg a way...
Assuming that the Dialog Inputs/Button extend React Native's own - then you can call:
onSubmitEditing and onChangeText
From the docs:
onSubmitEditing
Callback that is called when the text input's submit button is
pressed. Invalid if multiline={true} is specified.
TYPE REQUIRED
function No
And
onChangeText
Callback that is called when the text input's text changes. Changed
text is passed as an argument to the callback handler.
TYPE REQUIRED
function No
It means something like below:
<Dialog.Input label="Email"
onChangeText={email => this.setState({email})}
value={this.state.email}
onSubmitEditing={
(event) => this.doSomethingWithSubmit(event)
}
>
</Dialog.Input>
UPDATE
So I have tested this, and it works as below - side note - I'm using Typescript so just remove the types ( : string) etc:
In Render
return (
<View>
<View>
<Button onPress={this.showDialog}>
<Text>Show Dialog</Text>
</Button>
<Dialog.Container visible={true}>
<Dialog.Title>Password Recovery</Dialog.Title>
<Dialog.Input label="Email" onChangeText={(email : string) => this.handleEmail(email)}
></Dialog.Input>
<Dialog.Button label="OK" onPress={this.handleSendEmail} />
</Dialog.Container>
</View>
</View>
)
handleEmail:
private handleEmail = (email : string) => {
console.log("email");
console.log(email);
}
Result:
Further
As a side note of this project, I noticed when I used Live reload - that the Dialog was never re-rendered rather, rendered on top of the old Dialog. I would take this into consideration. Perhaps it was my environment, but everything else worked fine.
In our application, we're trying to use Datagrid within ReferenceField to create/modify/delete related records, as shown in https://marmelab.com/blog/2018/07/09/react-admin-tutorials-form-for-related-records.html
All the functionality shown in the tutorial works well, except the bulk-actions added in a recent react-admin update. Clicking these checkboxes gives
Uncaught TypeError: _this.props.onToggleItem is not a function
I believe this is because the onToggleItem prop is normally provided by the List component, however in this application, Datagrid doesn't have a parent List component.
Adding a List component between ReferenceManyField and Datagrid allows bulk select/delete to work after some changes to the style, however this causes another issue: the current displayed page (i.e. records 1-10, 11-20, etc) is stored per-resource in the store, and so it is possible to have a situation where the store says we're on page 2, and displays page 2, which is empty because there are only enough related items to fill one page.
Am I missing something here? Or is bulk-select inside ReferenceManyField not possible at the moment?
export const NetworksShow = (props) => (
<Show title={<NetworksTitle />} actions={<NetworksShowActions />} {...props}>
<ReferenceManyField addLabel={false} target="ipid" reference="acl-network">
<List style={{ margin: '0px -24px -16px -24px' }} {...props} actions={<NetworkACLCardActions ipid={props.id}/>} filter={{ ipid: _.has(props, 'id') ? props.id : undefined }}>
<Datagrid hasBulkActions={true}>
<ReferenceField label="Network" source="ipid" reference="networks">
<TextField source="name" />
</ReferenceField>
<TextField label="URL" source="url" />
<BWChip label="Action" source="wb" />
<EditButton />
<DeleteButton />
</Datagrid>
</List>
</ReferenceManyField>
</Show>
);
As a side-effect of https://github.com/marmelab/react-admin/pull/2365, it is now possible to use ReferenceManyField -> List -> Datagrid in the way described in the question.
For example, we're now doing the following:
<ReferenceManyField addLabel={false} target="groupid" reference="users">
<List
style={{ margin: '0px -24px -16px -24px' }}
filter={{ groupid: id }}
{...props}
>
<Datagrid hasBulkActions>
<LinkField label="Name" source="name" />
<LinkField label="Username" source="email" />
<FlexibleBooleanField label="Email" source="allowemail" />
<ACLChip label="User Access" source="aclid" />
</Datagrid>
</List>
</ReferenceManyField>
Bulk actions works with the above, and any issues with pagination are avoided as react-admin now checks and modifies pagination if nothing appears on the current page.
As I've understood from the documentation, Datagrid is just an iterator "dumb component".
It just "shows" things that the parent - usually List (connected component) or in your case ReferenceManyField - element previously has fetched.
Thus I think that BulkActions can only be functional when provided by a List element.
For the second part of your issue, Lists should be used top-level and not within other elements that's why it breaks your pagination.
I implemented "DumbList" which takes data from parent component instead of loading it itself. This solves the problem:
import React from 'react';
import { ListController } from 'ra-core';
import { ListView } from 'ra-ui-materialui/esm/list/List';
export const DumbList = props =>
<ListController {...props}>
{controllerProps => {
let { data } = props
const ids = Object.keys(data || {})
const total = ids.length
return <ListView
{...props}
// This is important, otherwise bulkActionsToolbar ends up on very top of the page
classes={{ card: 'relative' }}
{...Object.assign(controllerProps, { data, ids, total })} />
}}
</ListController>