Search code examples
admin-on-restreact-admin

React-Admin | Cannot upload a file using FileInput


First time with React-Admin. I am using it to create a panel that basically monitors some parameters that I get from an API. However, one section requires a .csv file to be uploaded. I am trying to implement it with FileInput but I am unable to catch the file. I don't understand how to do it.

File selection step (from pc to browser) is working properly, but my problem is that I cannot handle the file after that step. I read the docs, but I don't know how to do it. I tried many different ways but I am getting crazy.

Below is the basic code. I guess I have to add a handler or something similar but, how? I have little experience with React too. I know the basics, but I just built a couple of (super) simple apps. Just for learn.

// UploadFile.js
...

export const UploadSection = props => (
    <SimpleForm>
        <FileInput source="csvFile" label="Upload file (.csv)" accept="text/csv" >
            <FileField source="src" title="title" />
        </FileInput>
    </SimpleForm>
);


// App.js
...

const App = () => (
    <Admin dataProvider={dataProvider} authProvider={authProvider} >
        ...
        <Resource name="uploadSection" list={UploadSection} />
        ...
    </Admin>
);

The question:

  1. How can I catch the .csv file?

Thanks in advance!


Solution

  • After working on it during hours I got it working.

    First problem (the one I commented @selens answer): I got Uncaught TypeError: _this.props.save is not a function because I wasn't working in Create or Edit View. It seems you need to use FileInput in Create or Edit Views. If not, Save button won't work.

    From docs:

    save: The function invoked when the form is submitted. This is passed automatically by react-admin when the form component is used inside Create and Edit components.

    Second problem: In my case I upload one file at a time (multiple={false} in FileInput). However, the code addUploadFeature.js is ready to use with multiple files. So, I edited part of addUploadFeature.js to upload just one file. See the complete file below.

    // addUploadFeature.js
    
    const convertFileToBase64 = file => new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsDataURL(file.rawFile);
    
      reader.onload = () => resolve(reader.result);
      reader.onerror = reject;
    });
    
    const addUploadFeature = requestHandler => (type, resource, params) => {
    
      if (type === 'UPDATE' && resource === 'myResource') {
      
          if (params.data.myFile) {
    
              // NEW CODE HERE (to upload just one file):
              const myFile = params.data.myFile;
              if ( !myFile.rawFile instanceof File ){
                  return Promise.reject('Error: Not a file...'); // Didn't test this...
              }
    
              return Promise.resolve( convertFileToBase64(myFile) )
                  .then( (picture64) => ({
                      src: picture64,
                      title: `${myFile.title}`
                  }))
                  .then( transformedMyFile => requestHandler(type, resource, {
                      ...params,
                      data: {
                          ...params.data,
                          myFile: transformedMyFile
                      }
                  }));
          }
      }
      return requestHandler(type, resource, params);
    };
    
    export default addUploadFeature;
    

    After all, I was able to send the file to the server in Base64 format.

    Hope this to be useful for somebody in the future ;)