Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Doc] Update DataProvider File Upload Documentation To Leverage withLifeCycleCallbacks #9022

Merged
merged 1 commit into from
Jun 16, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 36 additions & 39 deletions docs/DataProviders.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,56 +287,51 @@ Check the [withLifecycleCallbacks](./withLifecycleCallbacks.md) documentation fo

## Handling File Uploads

As Data Providers are just objects, you can extend them with custom logic for a given method.
You can leverage [`withLifecycleCallbacks`](#adding-lifecycle-callbacks) to add support for file upload.

For instance, the following Data Provider extends the `ra-data-simple-rest` provider, and stores images passed to the `dataProvider.update('posts')` call as Base64 strings. React-admin offers an `<ImageInput />` component that allows image upload:

```js
import { withLifecycleCallbacks } from 'react-admin';
import simpleRestProvider from 'ra-data-simple-rest';

const dataProvider = simpleRestProvider('http://path.to.my.api/');

const myDataProvider = {
...dataProvider,
update: (resource, params) => {
if (resource !== 'posts') {
// fallback to the default implementation
return dataProvider.update(resource, params);
}

const dataProvider = withLifecycleCallbacks(simpleRestProvider('http://path.to.my.api/'), [
{
/**
* For posts update only, convert uploaded image in base 64 and attach it to
* the `picture` sent property, with `src` and `title` attributes.
*/

// Freshly dropped pictures are File objects and must be converted to base64 strings
const newPictures = params.data.pictures.filter(
p => p.rawFile instanceof File
);
const formerPictures = params.data.pictures.filter(
p => !(p.rawFile instanceof File)
);

return Promise.all(newPictures.map(convertFileToBase64))
.then(base64Pictures =>
base64Pictures.map(picture64 => ({
src: picture64,
title: `${params.data.title}`,
}))
)
.then(transformedNewPictures =>
dataProvider.update(resource, {
data: {
...params.data,
pictures: [
...transformedNewPictures,
...formerPictures,
],
},
})
resource: 'posts',
beforeUpdate: async (params, dataProvider) => {
// Freshly dropped pictures are File objects and must be converted to base64 strings
const newPictures = params.data.pictures.filter(
p => p.rawFile instanceof File
);
const formerPictures = params.data.pictures.filter(
p => !(p.rawFile instanceof File)
);
},
};

return Promise.all(newPictures.map(convertFileToBase64))
.then(base64Pictures =>
base64Pictures.map(picture64 => ({
src: picture64,
title: `${params.data.title}`,
}))
)
.then(transformedNewPictures =>
dataProvider.update(resource, {
data: {
...params.data,
pictures: [
...transformedNewPictures,
...formerPictures,
],
},
})
);
}
}
]);

/**
* Convert a `File` object returned by the upload input into a base 64 string.
Expand All @@ -355,6 +350,8 @@ const convertFileToBase64 = file =>
export default myDataProvider;
```

**Tip**: use `beforeSave` instead of `beforeUpdate` to do the same for both create and update calls.

You can use the same technique to upload images to an object storage service, and then update the record using the URL of that stored object.

## Adding Custom Methods
Expand Down