3

I'm using admin-on-rest. What a great framework ! It is working quite well for my flat resources.

I'm retrieving a list of projects /projects. I've implemented a ProjectEdit View to edit a given project /projects/:id

export const ProjectEdit = props => {
    const projectId = props.match.params.id;

    return (
        <Edit title={<ProjectTitle />} {...props}>
            <TabbedForm>
                <FormTab label="Project">
                    <DisabledInput source="id" />
                    <TextInput source="name" />
                </FormTab>
                <FormTab label="Companies">
                    // WHAT Should I put here to edit my companies list ???
                </FormTab>
            </TabbedForm>
        </Edit>
    );
};

I'd like to implement a new tab from which I'd be able to add / remove companies from my project.

GET /projects/:id/companies

{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 2,
            "name": "My Company"
        }
    ]
}

POST /projects/:id/companies

DELETE /projects/:id/companies/:company_id

I've tried to use a ReferenceManyField but I'm unable to configure it since my API requires a custom GET. My projects don't have any reference to companies. I can't find any example on how to perform it.

Any clues please ? :)


EDIT1: I'm able to display a list of my project's companies using @malisbad answer. But I'm still not able to display it for edition (eg: Using a ReferenceArrayInput + SelectArrayInput)

BaptWaels
  • 1,646
  • 2
  • 14
  • 17

2 Answers2

3

You have to use a custom restClient. I had the same problem, so if you haven't already, create it.

Then look at how the data comes through to each method that you want to have subresources for and modify the URL and request that you'll fire off from there.

For example, in GET_MANY_REFERENCE I have target contain an ENUM that specifies that I'm looking for a subresource.

let url = `${apiUrl}/${resource}`;
case GET_MANY_REFERENCE: {
    let target;
    try {
      target = JSON.parse(params.target);
    } catch (err) {
      target = {};
    }

    /*
      Reference fields do not support the format of
      /<resource>/<resource id>/<subresource> so the target parameter is used
      to instead indicate the subresource call. See
      https://marmelab.com/admin-on-rest/Fields.html#referencefield
      for details on reference fields
    */
    if (target && target[ENUMS.SUBRESOURCE_IDENTIFIER]) {

      /*
        If a resource ID is present, it's because the base resource doesn't match the
        host resource and needs to use its own ID, not the host resource ID.
      */
      if (target[ENUMS.RESOURCE_ID]) {
        url = `${url}/${target[ENUMS.RESOURCE_ID]}/${target.subresource}`;
      } else {
        url = `${url}/${params.id}/${target.subresource}`;
      }
    }

You can then extend this to other parts of your REST client

Malisbad
  • 189
  • 1
  • 7
  • Thank you for your answer. With your method, I'm able to display the list of companies inside my project in a ReferenceManyField. But I'm still not able to display it for edition (eg: Using a ReferenceArrayInput + SelectArrayInput) – BaptWaels Nov 21 '17 at 09:32
  • Using the target in this way saved me from a lot of headaches. And it describes what the component is to fetch rather well too. I was originally passing in `base_resource//nested_resource` and doing some string manipulation in the dataProvider to insert the base_resource_id between the "//" but the base resource must match the parent so this was breaking things. – mexitalian Aug 22 '18 at 17:22
2

I've found a solution to my problem. I'm not really happy with it but it works... I've created a Datagrid to remove the given company from the project. The Button gets as params record, resourceId.

I've also added a ReferenceInput to let me add one company at a time when the user hit Save

I've used a custom RestClient.js to handle GET_MANY_REFERENCE call and use the given url to retrieve my project's companies. I've done the same to handle UPDATE when the user hit save to add a new company.

EditProject.js :

<FormTab label="Entreprises">
    <ReferenceManyField label="Entreprises" reference="companies" target={{ resource: "projects", resourceId: projectId, subresource: "companies" }} allowEmpty>
        <Datagrid>
            <TextField source="id" />
            <TextField source="name" />
            <RemoveBtn resourceId={projectId} />
        </Datagrid>
    </ReferenceManyField>

    <ReferenceInput label="Company to Add" source="companyToAdd" reference="companies" allowEmpty>
        <SelectInput optionText="name" />
    </ReferenceInput>
</FormTab>

RemoveBtn.js :

export class RemoveBtn extends React.Component {
    handleRemove = () => {
        const {record, resourceId } = this.props;
        projectsService.removeCompanyFromProject(resourceId, record.id).then(() => window.location.reload());
    };

    render() {
        return <FlatButton label="Retirer" secondary onClick={this.handleRemove} />;
    }
}

Hope it helps...

BaptWaels
  • 1,646
  • 2
  • 14
  • 17
  • Yes, unfortunately, creation/edition of sub entities is not supported out of the box currently. You'll have to implement a custom component which would trigger the actions required to create a company – Gildas Garcia Nov 23 '17 at 15:39