Import an Excel spreadsheet into the backend system by converting it into binary data using readAsArrayBuffer in a Javascript/Angular environment

I need to upload an excel file through the UI, read it as binary data, and then send that data to a backend API.

Currently, I am using a File reader to read the file in binary format as shown below. I then pass the result of this reading to my Node.js controller to call the API:

fileReader.readAsBinaryString(this.file);

However, when attempting to process this on the backend, I encounter an error.

If I use fileReader.readAsArrayBuffer(this.file), I run into issues passing it to the controller since it is an object and not a string.

Does anyone have suggestions on how to overcome this challenge? I would like to successfully transmit the data obtained from readAsArrayBuffer to the API.

Answer №1

If you are utilizing Angular 2+, a method to send files to your server is by using the FormData in conjunction with HTTPClient (@angular/common/http). Assuming you are working with TypeScript, and upon clicking upload, you trigger a function named upload. Below is a straightforward example that can serve as a starting point for your scenario. The file will be transmitted as binary data:

import { HttpClient } from '@angular/common/http';

export class MyFormService {

 constructor(private _http: HttpClient) {}

 upload(data: IDataModel): Promise<IMyServerResponse> {
    return new Promise(async (resolve, reject) => {
      const url = 'https://example.com/api/';

      const formData = new FormData();
     
     //If dealing with a single attachment, consider this approach ---------------------------
     //For precaution, make sure to encode or replace any special characters in the fileName.
     //The function this.parseFileName handles this task.
     const name = this.parseFileName(data.attachment.name);
     formData.append('attachment', data.attachment.file, name);
     //-----------------------------------------------------------------------


      //Alternatively, if handling multiple files, consider this method ---------------------
      //Pay attention to the [] after attachment;
      for (const item of data.attachmentList) {
        
        const name = this.parseFileName(item.name);
        formData.append('attachment[]', item.file, name);
      }
     //-----------------------------------------------------------------------

      //Here, you post your form data while reporting progress -----------------
      await this._http.post(url, formData, { reportProgress: true, observe: 'events', responseType: 'json' })
        .subscribe(async event => {
            if (event.type === HttpEventType.UploadProgress) {
               //You can monitor the progress based on event.loaded 
               //divided by event.total and display it to the user.
               
               //Code omitted 
               ...
               ...
            }

            if (event.type === HttpEventType.Sent) {
              //Indicates successful transmission of data to the server.
              //Based on your server configuration, you can modify the request according to 
              //the form field.
            }

            if (event.type === HttpEventType.Response) {
              const serverResponse = event.body as IMyServerResponse;

              //Code omitted
              ...
              ...
              ...

              resolve(serverResponse);
            }
          },
          error => {
            let errorMessage;

            //Code omitted
            ...
            ...
            ...

            reject(error);
          });
    });
  }
}

PHP backend implementation for receiving files:

<?php


namespace App\Http\Controllers;


use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

abstract class BaseController extends Controller
{

  //Attachment
  /**
   * @throws Exception
   */
  public function retrieveAttachment(string $id): Response
  {
    $parsedId = intval($id);

    if (is_null($id)) {
      throw new Exception("Empty ID");
    } else if (!is_numeric($parsedId)) {
      throw new Exception("Invalid ID");
    }

    $data = $this->show($parsedId);

    // File type
    $file_type = mime_content_type($data->icon);
    $data->file_type = $file_type;

    //File extension
    $tmp = explode('.', $data->icon);
    $file_ext = strtolower(end($tmp));

    //File content
    $fileData = fopen($data->icon, 'rb');
    $size = filesize($data->icon);
    $fileContent = fread($fileData, $size);
    fclose($fileData);
    
    
    return response()->make($fileContent, 200, [
      'Cache-Control' => 'no-cache private',
      'Content-Type' => $file_type,
      'Content-length' => strlen($fileContent),
      'file_name' => $data->name,
      'file_type' => $file_type,
      'file_size' => $size,
      'file_ext' => $file_ext,
      'Content-Transfer-Encoding' => 'binary',
      'Access-Control-Expose-Headers' => 'file_name, file_type, file_size, file_ext'
    ]);
  }
}

Javascript/Angular backend for SharePoint on-premises (<= 2019)

import { Injectable } from '@angular/core';
import { Location } from '@angular/common';
import { ActivatedRoute } from '@angular/router';


import { SpCore } from 'my-beutiful-service.service';
import { sp } from '@pnp/sp/presets/core';
import "@pnp/sp/attachments";
//..
//..
//..
//.. other imports

@Injectable({
  providedIn: 'root'
})
export class CoreServicesDataSaveMainFormService {

  constructor(
  private _data: CoreServicesDataMainService,
  //...
  //...
  ) {}

    private populateFiles(attachmentsData: IAttachmentData[]): IAttachmentFileInfo[] {
        const attachments: IAttachmentFileInfo[] = [];
        const userAttachments: IAttachmentData[] = attachmentsData.filter(x => x.new);

        //This prepares the received file
        for (const attachment of userAttachments) {
          if (attachment.file != null) {
            const name = attachment.file.name;
            const content = new Blob([attachment.file], { type: attachment.file.type });
            attachments.push({ name, content });
          }
        }

        return attachments;
      }
    }

    private add(listItemId, listName, attachments, baseUrl) {
        const base = baseUrl == null ? SpCore.baseUrl : baseUrl;
        return new Promise((resolve, reject) => {
            sp.configure(SpCore.config, base).web.lists.getByTitle(listName).items.getById(listItemId).attachmentFiles.addMultiple(attachments)
                .then(() => {
                resolve({ code: 200, description: 'Success!', message: 'The attachments has been added successfully.' });
            })
                .catch(reason => {
                SpCore.showErrorLog(reason);
                reject([]);
            });
        });
    }

    private addAttachment(listItemId, listName, attachments, baseUrl) {
        const base = baseUrl == null ? SpCore.baseUrl : baseUrl;
        return new Promise((resolve, reject) => {
            sp.configure(SpCore.config, base).web.lists.getByTitle(listName).items.getById(listItemId).attachmentFiles.addMultiple(attachments)
            .then(() => {
                resolve({ code: 200, description: 'Success!', message: 'The attachments has been added successfully.' });
            })
            .catch(reason => {
                SpCore.showErrorLog(reason);
                reject([]);
            });
        });
    }

  async save() {
    const attachments: IAttachmentFileInfo[] = this.populateFiles(this._data.attachments);

    const data: IDatabaseFields = {
      field1: this._data.field1,
      field2: this._data.field2,
      field3: this._data.field3,
      field4: this._data.field4,
      field5: this._data.field5
    };

    try {
      //Creating item
      const iar: ItemAddResult | ISpCoreResult = await this.add(this._service.listName, data, this._environment.fullBaseUrl);
      this._loading.status('Item criado!');

      //Adding attachments to the sharepoint list item
      await this.addAttachment(id, this._service.listName, attachments, this._environment.fullBaseUrl);

      //Process
      this.processFinalEvents(returnToSource);      
    } catch (reason) {
      //..catch error
    } 
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue with escaping dialog in Bootstrap using the ESC key

My dialog is not responding to the escape key, any ideas on what could be causing this issue? <div *ngIf="visible" class="overlay"> <div role="dialog" class="overlay-content" tabindex="-1"> <div class="modal-dialog" [ngClass]= ...

When trying to call a function from a different component, the object inside the function is not being

Sorry for not giving a proper title to my question. Let me explain the problem I am facing. I have two Components - A and B. In Component B, there is a function called saveIndCustData which emits and saves data. export class CustomerformComponent implemen ...

Once the hidden DIV is revealed, the Youtube video within it begins to load

I currently have a hidden DIV on my website that contains a YouTube clip. My goal is to load the video in the background once the page has fully loaded, so that it's ready to play when the user clicks the button to reveal the DIV. However, at the mo ...

Substitute the label with the word

Imagine having a snippet of HTML code like this: "Hi there, my <strong>name</strong> is Nanoo." Is there a way to swap out the <strong> tag with another string? For instance: "Hi there, my **name** is Nanoo." (This replaces the <s ...

What is the process for restarting the timer within a timer controlled by the react-countdown component?

Looking for guidance on how to implement a reset() function in ReactJS and JavaScript to reset a timer when the "Reset Clock" button is clicked on my webpage. The goal is to have the timer return to its initial value. Open to suggestions on how to achieve ...

Use jQuery to toggle open all div elements simultaneously

I have a script that I created and it's functional, but not working exactly as intended. I developed this code because I couldn't find any existing code to modify HTML: <div class="corpo"> <div class="menu-segmento"> < ...

Preserving the top line or heading while cutting through a table

In my HTML, I have a table with the following structure: <table id="table"> <tr> <td>ID</td> <td>Place</td> <td>Population</td> </t ...

Are there any substitute proxy servers that are capable of bypassing CORS restrictions using local IP addresses?

Successfully bypassing CORS for AJAX requests to public IP addresses using proxy servers has been a game-changer. Is there a similar approach that can be utilized for local IP addresses when the server is hosted off-site? Unfortunately, I lack the abilit ...

Error: Trying to utilize the 'replace' method on a null value is not possible

When I type "_.template($('#pranks-list').html())" into the Chrome JS console, it actually works fine >> _.template($('#pranks-list').html()) function (a){return e.call(this,a,b)} In my app.js file // Views window.PranksLis ...

What is the best way to ensure the remaining PHP script is executed after using json_encode()?

My current project involves creating a form with four input fields: name, email, phone, and message. To handle the submission process, I am utilizing JavaScript in conjunction with Ajax to send the user inputs to a PHP file for validation and mailing using ...

The child component is failing to detect changes, consider using alternative methods like ngDoCheck to update the component's value

Within the childComponent @input() method, I am sending an array of objects where each object has 3 properties: name, id, and selected (boolean). My goal is to change only the selected property in the array and pass it to the child component for rendering. ...

Having difficulty uploading an image to Facebook through the graph API

I have a requirement to upload a photo to Facebook using the Javascript SDK, but I am experiencing some difficulties: Firstly, FB.login(function (response) { if (response.authResponse) { va ...

Express: fetch not capable of setting cookie

I am implementing a cookie setting feature with Express, using the code snippet below: app.use(require('cookie-parser')()); app.get('/a', function (req, res) { console.log(req.cookies); res.cookie('aaa', 'bbb&apo ...

Django fails to send back an ajax response when using the dataType parameter set to "JSON"

My goal is to send JSON to the server and receive a CSV in return. Below is the Ajax code I am using: var data = {"data":1} $.ajax({ type: "POST", url: "api/export_csv", data:JSON.stringify(data), // dataType: "JSON", // i ...

Steps to extract the file name prior to uploading and transfer it to a different text input box without using fakepath

I need help with uploading an image to a folder on the server and then retrieving the image name without the fakepath. Here is my code snippet for file upload in PHP: <?php if (($_FILES['my_file']['name']!="")){ // Specify where th ...

Attaching and detaching children to and from parents using A-Frame

I'm currently working on developing an application similar to Google Street View that is able to capture and display images in a 360 Equirectangular format using Aframe. https://i.sstatic.net/hDSCv.gif One idea I have been considering involves makin ...

searching for unspecified information in node.js mongodb

I am encountering an issue while trying to retrieve data from the database after a recent update. The code snippet result.ops is not functioning as expected in MongoDB version 3.0. I am receiving undefined in the console output. Can someone guide me on the ...

The Typescript Module augmentation seems to be malfunctioning as it is throwing an error stating that the property 'main' is not found on the type 'PaletteColorOptions'

Recently, I've been working with Material-UI and incorporating a color system across the palette. While everything seems to be running smoothly during runtime, I'm facing a compilation issue. Could someone assist me in resolving the following err ...

Modify the hue of the div as soon as a button on a separate webpage is

Looking for assistance with a page called "diagnosticoST" that contains four buttons (btn-institucional, btn-economico, btn-social, btn-natural). These buttons have different background colors until the survey inside them is completed. Once the user comple ...

What is the method for assigning a value to a JSON object using data from another JSON object?

I am faced with the task of setting the seqNo property in one JSON object, b, based on the id from another JSON object, a. How can I achieve this? var a = [{id: "Make", seqNo: 4}, {id: "Model", seqNo: 1}, {id: "XModel", seqNo: 2 ...