ReferenceField keeps showing loading bar on null value - admin-on-rest

I have following List component where customerid and technicianid are
ReferenceField. Sometimes I have technicianid as null. So the UI keeps showing the loading bar (as shown in the image below).
Question:
How can I tell the ReferenceField to handle null and just show the empty string.
export const AppointmentList = (props) => (
<List title="All Appointments" {...props}>
<Datagrid>
<ReferenceField source="customerid" reference="customers" label="Customer" >
<TextField source="name" />
</ReferenceField>
<TextField source="name" label="Name" />
<DateField source="scheduleddt" label="Schedule Date" />
<ReferenceField source="technicianid" reference="technicians" label="Technician" >
<TextField source="name" />
</ReferenceField>
<DateField source="createddatetime" label="Created" />
</Datagrid>
</List>
);

You'll need the 'allowEmpty' attribute.
export const AppointmentList = (props) => (
<List title="All Appointments" {...props}>
<Datagrid>
<ReferenceField source="customerid" reference="customers" label="Customer" >
<TextField source="name" />
</ReferenceField>
<TextField source="name" label="Name" />
<DateField source="scheduleddt" label="Schedule Date" />
<ReferenceField source="technicianid" reference="technicians" label="Technician" allowEmpty>
<TextField source="name" />
</ReferenceField>
<DateField source="createddatetime" label="Created" />
</Datagrid>
</List>
);
https://marmelab.com/admin-on-rest/Inputs.html#referenceinput

We are currently working on it :)

Related

Added 'search function' using React-admin package, but not working, why?

I am using React-admin to create a customer dashboard where they can find their invoices for all months. Now I would like to add search function to this so that customers can search invoices according to any field,say entity_name.
I am able to add search element on ui, but its not working.
I added search functionality by importing {Filter, TextInput} from React-admin. And I am using data from "ra-data-simple-rest"; and running sever on port 5000 in my local machine.
Here is my code:
const InvoiceFilter = (props) => (
<Filter {...props}>
<TextInput source="entity_name" alwaysOn />
</Filter>
);
const InvoiceList = (props) => {
return (
<List {...props} filters={<InvoiceFilter />}>
<Datagrid>
<TextField source="id" />
<TextField source="entity_name" />
<DateField source="period_start" />
<DateField source="period_end" />
<TextField source="total" />
</Datagrid>
</List>
);
};
You should use proper components for the filter function.
the filters props is for FilterForm
<FilterForm filters={postFilters} />
Placing the filters props in List component is not doing anything.
Create proper filter and pass it to a proper component like shown in the documentation here
Based on the docs, you could try:
const invoiceFilters = [
<TextInput source="entity_name" alwaysOn />
);
const InvoiceList = () => {
return (
<List filters={invoiceFilters}>
<Datagrid>
<TextField source="id" />
<TextField source="entity_name" />
<DateField source="period_start" />
<DateField source="period_end" />
<TextField source="total" />
</Datagrid>
</List>
);
};

Datagrid in Create, Edit page

I want to create a Datagrid inside Create, Edit page to display and manage n-to-n relationship. But I don't know how to pass props into List and Datagrid and what props should be passed.
The Resource to manage this Datagrid named caregiver_student and I put it in my custom restClient file.
Basic info
Relationship info
Here is my code:
<Edit title={<CaregiverTitle />} {...props}>
<TabbedForm>
<FormTab label="Personal Info">
<DisabledInput source="id" />
<TextInput source="name" />
<TextInput source="email" />
<TextInput source="phone" />
<RadioButtonGroupInput source="account_type" choices={[
{ id: 10, name: 'Caregiver' },
{ id: 20, name: 'Guardian' },
]} optionText="name" optionValue="id" />
<BooleanInput source="status" label="Active"/>
</FormTab>
<FormTab label="Relationship">
<List actions={<RelationActions/>} location={false} title={" "}>
<Datagrid>
<TextField source="id" />
<TextField source="name" label="Student"/>
<TextField source="relationship" />
<EditButton />
<DeleteButton />
</Datagrid>
</List>
</FormTab>
</TabbedForm>
</Edit>
Thank you for your help!
The linked resources should be enclosed in a ReferenceManyField
You can find a complete example in the demo,
especially the Customers Edit component
Someone started a PR which might help: https://github.com/marmelab/admin-on-rest/pull/744
I have a similar page with a tab that lists "Batchunits" that belong to a particular "batchid".
<FormTab label="resources.batches.tabs.batchunits">
<ReferenceManyField addLabel={false} reference="Batchunits" target="batchid">
<Datagrid bodyOptions={{ stripedRows: true, showRowHover: true}} >
<TextField source="unitcode" />
<DateField source="harvested" />
<BooleanField source="contaminated" label="Contaminated"/>
<TextField source="note" style={{ maxWidth: '10em', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} />
<EditUnitButton />
</Datagrid>
</ReferenceManyField>
</FormTab>
But in this setup, Formtab will not accept a Create "button" to create a record of another resource. e.g another "Batchunit. Would be very useful to create another linked Batchunit. Don't know how to do that...

admin-on-rest: Access row's column data within a Datagrid component

I have a List view where I want to render a ReferenceField field based on the value of the current row being rendered in the table that the Datagrid component creates.
How can I access the current row's data? (the values of the columns of the current row).
I tried record.processed but I get an error saying that the record object doesn't exist (processed is a column in the record that I want to check in order to format the field). I also tried resource.processed, this.props.processed, and this.props.record.processed with no success.
The piece of code that shows what I'm trying to do is the following:
<List title="Sales Inquiries" filter={{ request_type: 'sales' }} {...props}>
<Datagrid>
<TextField source="id" />
<TextField source="firstname" label="First Name" />
<TextField source="lastname" label="Last Name" />
<TextField source="company" />
<TextField source="email" />
<DateField source="timestamp" label="Received" />
{record.processed ?
<ReferenceField label="Processed By" source="processedBy_id" reference="Users">
<TextField source="username" />
</ReferenceField>
: <span>Nobody</span> }
<ShowButton />
</Datagrid>
</List>
EDIT
Did as suggested by #kunal pareek Applied a HOC to the ReferenceField field that modifies it in order to show the proper content as follows:
const CustomField = (props) => (
<span>
{props.record.processed ?
<ReferenceField label="Processed By" source="processedBy_id" reference="Users">
<TextField source="username" />
</ReferenceField>
: <span>Nobody</span> }
</span>
);
the record is not really available at the location you want as a variable. It is passed to the component as a prop.
So you can do this.
<List title="Sales Inquiries" filter={{ request_type: 'sales' }} {...props}>
<Datagrid>
<TextField source="id" />
<TextField source="firstname" label="First Name" />
<TextField source="lastname" label="Last Name" />
<TextField source="company" />
<TextField source="email" />
<DateField source="timestamp" label="Received" />
<CustomField />
<ShowButton />
</Datagrid>
</List>
const CustomField = (props) => (
{props.record.processed ?
<ReferenceField label="Processed By" source="processedBy_id" reference="Users">
<TextField source="username" />
</ReferenceField>
: <span>Nobody</span> }
)
Above is just a simple example. I have taken your code straight and reformatted it, so it might not work straightaway. But I have been using this method to change the values of my components in several places.
You can also use HOCs. You can find examples here
https://marmelab.com/admin-on-rest/Theming.html
The dependent-input addon can help you with that.

REST URL customization

I had to change in the restclient after like this:
var parentresource = '';
switch (resource) {
case 'details':
parentresource = `products/${params.id}/${resource}`;
break;
default:
parentresource = `${resource}`;
}**
url = `${apiUrl}/${**parentresource**}?${fetchUtils.queryParameters(query)}`;
break;
I have a EditView where in one tab I have got:
<ReferenceManyField addLabel={false} reference="details" target="id">
<Datagrid>
<NumberField source="quantity" label="Quantity" />
<TextField source="measurementUnit" label="Measurement" />
<NumberField source="purchasePrice" label="Purchase Price" />
<NumberField source="salesPrice" label="Sales Price" />
<NumberField source="discountPercent" label="Discount Percent" />
<NumberField source="salesTaxPercent" label="Sales Tax Percent" />
<TextField source="supplier" label="Supplier" />
<DateField source="createdDate" label="Created Date" />
<TextField source="status" label="Status" />
<EditButton basePath="/products" />
</Datagrid>
</ReferenceManyField>
When I click EditButton the url in the browser needs to needs to be http://localhost:5000/#/details/1?_k=5f7qc1 but the url to grab data from should be http://localhost:5000/api/products/2/details/1
Any easier way to do this?
That's the job of a custom restclient

Is there a way to use an if statement before showing the show page?

Is there a way to do an if statement before showing the show page?
For instance if the id of the element I clicked on with the show button end with ".log" I want to have the show page look like this:
export const reportShow = ({ ...props }) => (
<Show title="Log" {...props}>
<SimpleShowLayout>
<ReferenceManyField label="Log" reference="archivedfiles" target="id">
<Datagrid>
<TextField source="id" label="Line" />
<TextField source="timestamp" label="Timestamp" />
<TextField source="severity" label="Severity" />
<TextField source="message" label="Message" />
</Datagrid>
</ReferenceManyField>
</SimpleShowLayout>
</Show>);
But if the id ends with .txt I want the show page to show a Report page which would have this:
export const reportShow = ({ ...props }) => (
<Show title="Report" {...props}>
<SimpleShowLayout>
<TextField source="id" label="Report Name" />
<TextField source="rmessage" label="Message" />
</SimpleShowLayout>
</Show>);
What would be the best way to go about this?
Maybe the aor-dependent-input addon can help you with that.
I ended up getting this to work by doing this:
export const archivedShow = ({ ...props }) => {
if (props.match.params.id.endsWith("txt")){
return (<Show title="Report" {...props}>
<SimpleShowLayout>
<ReferenceManyField label="Report" reference="archivedfiles" target="id">
<Datagrid>
<FormattedReportView/>
</Datagrid>
</ReferenceManyField>
</SimpleShowLayout>
</Show>
);
}
else {
return (
<Show title="Log" {...props} filters={< LogFilter/>}>
<SimpleShowLayout>
<ReferenceManyField label="Log" reference="archivedfiles" target="id">
<Datagrid>
<TextField source="id" label="Line" />
<TextField source="timestamp" label="Timestamp" />
<TextField source="severity" label="Severity" />
<TextField source="message" label="Message" />
</Datagrid>
</ReferenceManyField>
</SimpleShowLayout>
</Show>
);
}
}

Resources