How to download an Excel file (xlsx) using AngularJS and WebApi


I am currently working on a project that requires me to download a report in xlsx format. Despite successfully generating the report file on the server and receiving it on the client side, I am facing an issue where the file is not opening and is resulting in an invalid format error.

Here is the code snippet for the server side:

var output = await reportObj.GetExcelData(rParams);
    if (output != null){
        var result = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new ByteArrayContent(output.ConentBytes)
        };
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = output.FileName
        };
 return result;
 }


And here is the code for the client side:

        var saveData = function (response) {

        if (response.status === 200) {
            var reportData = response.data;

            var b = new Blob([reportData], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
            saveAs(b,"ReportFile.xlsx");//this is FileSaver.js function
        } else {
            console.log(response.statusText);
        }

    };


    $scope.getExcelFile = function(reportName, reportParams) {

        reportDataService.getExcelReportData(reportName, reportParams, saveData);

    }


The error message being displayed:
Excel could not open newFile.xlsx because some content is unreadable. Do you want to open and repair this workbook?

Upon clicking repair, the following error occurs: Excel cannot open this file.
The file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file.

I would appreciate any guidance on what steps I might be missing. It is worth noting that the same server-side file generator functions without errors in an ASP.Net forms application.
Thank you.

Answer №1

It appears that the missing response type configuration might be causing issues with your $http call. Here's a snippet of code showcasing how I handle downloading office files:

function download(url, defaultFileName) {
    var self = this;
    var deferred = $q.defer();
    $http.get(url, { responseType: "arraybuffer" }).then(
        function (data, status, headers) {
            var type = headers('Content-Type');
            var disposition = headers('Content-Disposition');
            if (disposition) {
                var match = disposition.match(/.*filename=\"?([^;\"]+)\"?.*/);
                if (match[1])
                    defaultFileName = match[1];
            }
            defaultFileName = defaultFileName.replace(/[<>:"\/\\|?*]+/g, '_');
            var blob = new Blob([data], { type: type });
            saveAs(blob, defaultFileName);
            deferred.resolve(defaultFileName);                    
        }, function (data, status) {
            var e = /* error */
            deferred.reject(e);
        });
    return deferred.promise;
}

Answer №2

After encountering the same issue where the content was in hex format, I found a solution by specifying the response type as arraybuffer. Here is the code snippet that resolved the problem:

$http({
    url: '/api/sendPMOToBackendUpdate',
    method: "POST",
    headers: {'Content-type': 'application/json'},
    data: backendTsData,
    responseType: 'arraybuffer'
}).success(function(data, status, headers){
    var file = new Blob([ data ], { type : 'application/vnd.ms-excel'});
    var defaultFileName ="TSC-"+$scope.user.name+"-"+$scope.user.ohrId+".xls";
    saveAs(file,defaultFileName);
}).error(function(err) {
    console.log('Error: ' + err);
});

Answer №3

If you want to save a file locally, all you need to do is include the following JavaScript code. Download it from this link: "https://github.com/eligrey/FileSaver.js/". Make sure your response data is in blob type.

I have already implemented this solution and it works perfectly.

function downloadfile(url,defaultFileName){
  var self = this;
    var deferred = $q.defer();
    $http.get(url, { responseType: "blob" }).then(
       function (data){
          saveAs(data.data, defaultFileName)
          deferred.resolve(defaultFileName);                    
        }, function (data) {
           var e = /* error */
            deferred.reject(e);
        });
        return deferred.promise;
}

Answer №4

While working with the Javascript library Excel Builder, I encountered a familiar issue. After some investigation, it turned out that the presence of a control character '\u001a' in the data was causing the problem.

To fix this issue, you can encode the control character using Excel's format as '_x001a_.'

To pinpoint the source of the problem, I followed these steps:

An .xlsx file is essentially a zipped XML file. Using software like 7-zip, navigate to the xl/ folder and locate the sharedString.xml file which contains all strings. Extract the file and view it with Notepad++. If any control characters are present, they may be the root cause of the issue.

Answer №5

To start, make sure you have the following modules installed:

import * as Excel from 'exceljs';
import * as fs from 'file-saver';

Within your function, include the following code:

 const workbook = new Excel.Workbook();
  var worksheet =  workbook.addWorksheet('sheet');
  worksheet.columns = [
    { header: 'Id', key: 'id', width: 10 },
    { header: 'Name', key: 'name', width: 32 }
  ];
 var buff = workbook.xlsx.writeBuffer().then(function (data) {
    var blob = new Blob([data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
    fs.saveAs(blob, "publications.xlsx");
  });

The module Fs allows access to the file system for downloading files. Additionally, images can be inserted by referring to the link here.

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

I encountered a problem with iteration where the results appeared perfectly fine, but upon rendering at the component level, the same field loaded with the last object instead

I am facing an issue with rendering the component level when it loads. After clicking on edit and calling the edit function, the data is properly loaded in console and all objects are shown. However, they do not render on the page level. Below is the code ...

Display a list of records retrieved from a Firebase query using ngFor to iterate through each instance

I'm currently using firebase and angular to work on a billing list project. The list contains data showing information for a specific month, you can refer to the imagehttps://i.stack.imgur.com/ZR4BE.png While querying the list was smooth, I encounte ...

Is there a way to use AJAX for transferring a value?

I am looking to transmit a value to a php-script (servo.php) that will then write the received data in a file (/dev/servoblaster). The script section of my HTML file (index.html): <script> function tiltt() { var tilt = document.getElementById("tilt ...

What is the method for showcasing a single Observable from an Array of Observables in Angular?

I am facing a challenge with displaying questions from an Observable-Array one by one. Currently, I can only display all the questions at once using *ngFor in my HTML. Here is my component code snippet: import { Component, OnInit } from '@angula ...

I am currently transferring cross-site forgery tokens through jQuery strings. However, on the subsequent page, I create a fresh token which means their original tokens will no longer align

Alright, so I've been storing the tokens in a session: Session::get('token', 'randomtokenstringhere'); Every time a form is submitted, whether successfully or not, I generate a new token and update their session token. But let&ap ...

Divide a collection of q promises into batches and execute them sequentially

In order to achieve my objective of copying files while limiting the number of files copied in parallel based on a defined variable, I decided to divide an array of promises using calls to fs.copy into packets. These packets are then executed in series by ...

An issue arises with Autocomplete when attempting an ajax request and an error is

I'm struggling to implement jQuery Autocomplete on a text box, but it's not functioning properly. Below is my script for retrieving autocomplete list from the database. However, I encounter an error that displays an alert with an error message. ...

What is the best way to direct users to an input field within a dynatree title?

I am currently utilizing Dynatree to display a tree view, and my goal is to focus on an input field within the dynatree title element. However, I am encountering an issue where the focus is being lost. My code attempts to address this problem but unfortun ...

Rotating arrows enhance the functionality of the accordion menu

I have successfully implemented a basic accordion with rotating arrows on click. Everything is working smoothly except for one issue: When I collapse one item and then try to collapse another, the previous arrow does not return to its default state. Is ...

Firefox won't trigger the `beforeunload` event unless I interact with the webpage by clicking on it

In my quest to handle the beforeunload event in Firefox, I've encountered a small hurdle. It seems to be working smoothly, but only if the user physically interacts with the page by clicking on it or entering text into an input field. Below is the co ...

The issue of Angular JQuery Datepicker failing to set the MinDate upon initialization

In my AngularJS project, I am using JQuery UI's Datepicker for the Date From and Date To fields. I have successfully bound the value to the model using a directive, and I have also implemented logic in the OnSelect function to ensure that the Date To ...

Breaking down arrays in Typescript

Let's say I have an array like this: public taskListCustom: any=[ {title: 'Task 1', status: 'done'}, {title: 'Task 2', status: 'done'}, {title: 'Task 3', status: 'done'}, {title: 'Task ...

A stationary webpage nested within a lively pathway on NuxtJS

I have a Nuxt app with a list of cars available at: /cars. You can select a specific car at /cars/:id. I would like to have a toolbar that routes to different views such as: /cars/:id/routes, /cars/:id/drivers, etc. Within the /cars/:id page, I have creat ...

Having trouble connecting through a network using WCF

I have implemented a WCF self-hosted service within a Windows Forms application for interaction with a handheld mobile device at a basic level. The service has been configured with basicHttp (http://localhost:8080/tagservice/basic), NetTCP (net.tcp://loca ...

Ways to implement a resize function in Angular JS without relying on the document and window objects

Is there a way to convert the following jQuery code into Angular JS without relying on Document and Window? Can we write the code without utilizing Document.ready and window? ...

The prop type 'lg' supplied to 'ForwardRef(Grid)' is not valid and has failed

This particular code snippet is responsible for managing the layout of components on the webpage. However, I have encountered some warning messages in the console: Warning: Failed prop type: The lg prop provided to ForwardRef(Grid) is invalid, it should ...

"Exploring the differences in parsing between route-specific and top-level generic approaches in Node

What are the benefits of utilizing top-level generic parsing: // parse application/x-www-form-urlencoded app.use(bodyParser.urlencoded({ extended: false })) // parse application/json app.use(bodyParser.json()) compared to route-specific parsing: // cre ...

How do you unfocus a React Native TextInput when a button is clicked?

Is there a way to remove the focus from a React Native textInput when clicking on a button? This is how my TextInput is set up: <TextInput onChangeText={onChange} value={searchQuery} placeholder="Start t ...

What could be causing the computed property in Vue 2 component to not return the expected state?

I'm encountering an issue with my Vue component where it fails to load due to one of its computed properties being undefined: Error: Cannot read properties of undefined (reading 'map') Here is the snippet of the computed property causing ...

The act of appending values to an array within a hash in Vue is not functioning as expected

I am currently working on implementing a feature that allows users to add multiple workers by clicking the "Add worker" button. However, I have encountered an issue where placing the workers array inside the management object prevents this feature from f ...