-1

I am using NodeJs with Multer to upload Excel file to the server. I am using this to upload excel file. My Excel file is in server transformed into zip file, which is not OK.

Later in my project, I need another API, which will download that same uploaded Excel file via Angular application and it need to be Excel. (If I upload pdf file, it stays pdf...)

NodeJs part of code:

Route:

const multer = require("multer");
const storage = multer.diskStorage({
  destination: (req: any, file: any, cb: any) => {
    cb(null, "utilities/uploaded-excels");
  },
  filename: (req: any, file: any, cb: any) => {
    // dolocis ime fila
    const name: string = file.originalname.toLowerCase().split(" ").join("-");
    cb(null, name + "-" + Date.now());
  },
});

// Upload excel file
router.patch(
  "/uploadFile/:id",
  multer({ storage: storage }).single("file"),
  verifyToken,
  containerController.uploadReportFile
);

Controller:

exports.uploadReportFile = async (req: any, res: any) => {
  try {

    let newExcelPath = {
      newExcelPath: "./utilities/uploaded-excels/" + req.file.filename,
    };

    await Container.findByIdAndUpdate(req.params.id, newExcelPath, {
      new: true,
    }).then((container: any) => {
      if (!container) {
        return res.status(404).send();
      }        
      res.status(200).json(container);
      
    });
  } catch (err) {
    console.log(err);
    res.status(404).json({ success: false, msg: err });
  }
};

Postman exmaple: enter image description here

Angular service:

uploadFile(
    id: string,
    file: File
  ): Observable<ServerResponse> {
    const fileData = new FormData();
    fileData.append("file", file, "title-of-file?");
    const url: string = this.apiUrl + "uploadFile/" + id;
    if (!this.token) {
      const authString = `Bearer ${this.token}`;
      httpOptions.headers = httpOptions.headers.append(
        "Authorization",
        authString
      );
    }
    return this.http.patch<ServerResponse>(url, fileData, httpOptions);
  }

component.ts where I upload file

onFileSelected(event: any) {
    this.selectedFile = <File>event.target.files[0];
    this.fileName = this.selectedFile.name;

    let ext = this.selectedFile.name.substring(
      this.selectedFile.name.lastIndexOf(".") + 1
    );

    if (ext.toLowerCase() == "xlsx") {
      this.fileType = true;
    } else {
      window.alert(this.alertType);
      this.fileType = false;
    }
    if (this.fileType) {
      this.fileOnHold = true;
    }
  }

  uploadFile() {
    if (!this.selectedFile) return;

    this.uploadFileSubs = this.containersService
      .uploadFile(this.id, this.selectedFile)
      .subscribe(
        (res: any) => {
          console.log(res);
        },
        (error) => {
          console.log(error);
        }
      );
  }

And an HTML part

<input
  type="file"
  name="file"
  id="document"
  style="display: none"
  (change)="onFileSelected($event)"
  accept="application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  #fileInput
/>
<button
  class="btn-dark small"
  style="white-space: nowrap"
  (click)="fileInput.click()"
>
  Choose file
</button>
devZ
  • 606
  • 1
  • 7
  • 23
  • Does this answer your question? [How to store a file with file extension with multer?](https://stackoverflow.com/questions/31592726/how-to-store-a-file-with-file-extension-with-multer) – Lawrence Cherone Oct 11 '22 at 16:52
  • 1
    please provide code for `storage`, multer doesn't store files as zips, additionally, the response in postman is showing it's not a zip, just does not have an extension which is normal – Lawrence Cherone Oct 11 '22 at 16:56
  • Sure, no problem. I added it in the beginning of my question. – devZ Oct 11 '22 at 16:58
  • so change this mess `const name: string = file.originalname.toLowerCase().split(" ").join("-"); cb(null, name + "-" + Date.now());` to save it as its proper filename with extension, like in the linked dupe – Lawrence Cherone Oct 11 '22 at 17:00
  • There is something wrong with the angular (service) side I guess. In postman it works, via Angular application it doesnt :( – devZ Oct 11 '22 at 17:45

1 Answers1

1

I solved the problem.

I changed the angular's uploadFile service. I removed the third parameter (file's name) when appending file to formData:

  uploadFile(
    containerId: string,
    file: File
  ): Observable<any> {
    const fileData = new FormData();
    let fileName = file.name.split(".")[0];

    fileData.append("file", file);
    const url: string = this.apiUrl + "uploadFile/" + containerId;
    if (!this.token) {
      const authString = `Bearer ${this.token}`;

      httpOptionsFile.headers = httpOptionsFile.headers.append(
        "Authorization",
        authString
      );
    }
    return this.http.patch<any>(url, fileData, httpOptionsFile);
  }

And I changed multer specifications for the router. I specified the file's extension directly in the name and removed it when fetching the name of original file (to prevent duplication of extensions):

const path = require("path");
const multer = require("multer");
const storage = multer.diskStorage({
  destination: (req: any, file: any, cb: any) => {
    cb(null, "utilities/uploaded-excels");
  },
  filename: (req: any, file: any, cb: any) => {
    // dolocis ime fila
    let fileName: string = file.originalname
      .split(".")[0]
      .toLowerCase()
      .split(" ")
      .join("-");

    cb(null, fileName + "-" + Date.now() + path.extname(file.originalname));
  },
});
devZ
  • 606
  • 1
  • 7
  • 23