22

I need to use the FileSaver.js (https://github.com/eligrey/FileSaver.js/) in my Angular2 application.

I know I can add it as a script file in main html page and it will work. But I was wondering what would be the best approach in case of an Angular 2 (TypeScript) application so that I can just call window.saveAs to save file.

Naveed Ahmed
  • 10,048
  • 12
  • 46
  • 85

4 Answers4

73

I managed to get it work using this approach (Angular-CLI):

npm install file-saver --save
npm install @types/file-saver --save

After that import Filesaver in component:

import * as FileSaver from 'file-saver';

And you can use it like this:

    let blob = new Blob([document.getElementById('exportDiv').innerHTML], {
            type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-16le"
        });
    FileSaver.saveAs(blob, "export.xls");    

As you can see, you don't have to add anything in angular-cli.json. Just install library and it's types, import it and you are ready to go.

Tomislav
  • 3,181
  • 17
  • 20
  • None of the other suggestions worked for me but this did the job nicely. – ceebreenk Jan 25 '17 at 08:39
  • Is there a way to trigger the prompt rather than auto-downloading? – Jeff Jul 06 '17 at 13:34
  • This worked great for me, but I didn't even need to install that second `@types/file-saver` package. Also: @JasonBourne, you misspelled "file" :P – jlh Jul 24 '17 at 14:00
  • Getting this error: Argument of type '{ imports: (typeof CommonModule | typeof FileSaver)[]; declarations: (typeof DashboardComponent |...' is not assignable to parameter of type 'NgModule'. Types of property 'imports' are incompatible. Type '(typeof CommonModule | typeof FileSaver)[]' is not assignable to type '(any[] | Type | ModuleWithProviders)[]'. Type 'typeof CommonModule | typeof FileSaver' is not assignable to type 'any[] | Type | ModuleWithProviders'. – pjay Jan 18 '18 at 05:36
  • praveen in order to help you can you share your component code with us? – Tomislav Jan 18 '18 at 06:37
  • 1
    I'm getting `FileSaver.saveAs is not a function`. It appears as if `FileSaver` I've imported is somehow in fact the function `saveAs`. It's as if there' a discrepancy between the @type and the implementation – ronif Jan 25 '18 at 12:31
  • 3
    you can save inside devDependencies: npm install @types/file-saver --save-dev – Luca Basilico May 29 '18 at 15:32
  • Solution worked for me, but it downloads the file in chrome instead of saving it in specified file location, is this expected or I am doing something incorrect? – RDV May 06 '20 at 23:50
  • 1
    @RDV, yeah it is by design. – Tomislav May 07 '20 at 21:49
  • If I just want to render and open the file using blob URL in new tab and let user decides weather to save it or not, in that scenario, would this library be useful to me? – Aakash Goplani Feb 19 '21 at 15:19
16

If you're using Angular-CLI to build your project, you can install it by running

npm install file-saver --save

Since there aren't any typings for FileSaver, I had to do:

declare module "file-saver";

in my typings.d.ts file.

Then, to use it:

// Import
import * as FileSaver from "file-saver";

//Implementation
FileSaver.saveAs(blob, filename);

For reference, these steps are taken from Angular-Cli's steps for installing third-party libraries

Edit 9/27/2017: It appears there is now a type definition for FileSaver.js according to the README instructions, so instead of the

declare module "file-saver"

you just need to

npm install @types/file-saver --save-dev
cbierman
  • 400
  • 5
  • 15
  • I have the same challenge described above, but i am not using the angular-cli. I installed the filesaver module, added it to my system.config.js. However, it when loading some filesaver dependency, it gave 404, because it could not find the .js extension to load them. Please help – mayowa ogundele Nov 24 '16 at 09:08
  • @Elliott08 It should! I've used it in an Angular 5 project, at least. – cbierman Mar 22 '18 at 15:49
4

Just doing npm install file-saver --save is a good start. You also need a typescript declaration file (like file-saver.d.ts or typings.d.ts) for this library is in plain javascript. Normally you would get it by doing npm install @types/file-saver but this package is currently outdated.

I have created a file-saver.d.ts for myself – just place it in your source directory.

file-saver.d.ts

declare function saveAs(data: Blob, filename: string, noAutoBOM?: boolean): void;
declare module 'file-saver' {
    export = saveAs;
}

Then you can use saveAs as follows:

your.ts

import saveAs = require('file-saver');
function save() {
    let blob = new Blob(['Hello world!'], { type: 'text/plain;charset=utf-8' });
    saveAs(blob, 'newcontrol.txt');
}

Of course, don't forget to update your loader's configuration.

For SystemJS you need something like this:

/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
  System.config({
    paths: {
      // paths serve as alias
      'npm:': 'node_modules/'
    },
    // map tells the System loader where to look for things
    map: {
      // our app is within the app folder
      app: 'app',

      // angular bundles
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',

      // other libraries
      'rxjs':                      'npm:rxjs',
      'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
      'file-saver':                'npm:file-saver'
    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        main: './main.js',
        defaultExtension: 'js'
      },
      rxjs: {
        defaultExtension: 'js'
      },
      'file-saver': {
        main: './FileSaver.js',
        defaultExtension: 'js'
      }
    }
  });
})(this);
Ted
  • 333
  • 2
  • 15
2

Even not a great way like other people mentioned, I prefer to use existing package from NPM which called ngx-filesaver. It is even works fine with Angular Universal.

Just do:

npm install file-saver ngx-filesaver --save


Include to your Module project:

...
import { FileSaverModule } from 'ngx-filesaver';
...
@NgModule({
  imports: [ FileSaverModule ]
})
...


Then load the service to your component:

....
import {FileSaverService} from 'ngx-filesaver';
...

@Component({
    ...
})
...
constructor(Http, private fileSaverService: FileSaverService) {
}

onSave() {
 workbook.xlsx.writeBuffer()
      .then( (buffer) => {

        //I am saving spreadsheed ( XLSX ) buffer here...
        this.fileSaverService.save(new Blob([buffer], { type: 'application/octet-stream'}), `${fileName}.xlsx`);

      });
}

More detail please visit: https://www.npmjs.com/package/ngx-filesaver

Bayu
  • 2,340
  • 1
  • 26
  • 31
  • ngx-filesaver depends on filesaver.js, which still doesn't solve the issue. – elliotwesoff Mar 19 '21 at 01:38
  • Not sure what do mean by "doesn't solve the issue", on the other answer in this thread, it even works by having a custom typescript definition: https://stackoverflow.com/a/41265382/3168185 . – Bayu Mar 19 '21 at 08:06
  • I got the same error still when installing the FileSaverService. Simply installing @types/file-saver didn't fix the issue for me either, probably because I'm using angular in strict mode. What did work was installing file-saver-es, referring to "file-saver-es" in my code, and then redirecting "file-saver-es" to @types/file-saver in my tsconfig.json. Sucks but it's the *only* configuration that worked for me. – elliotwesoff Mar 22 '21 at 23:31
  • 1
    Never had that experience before. Thanks for sharing. Hope that helps others. – Bayu Mar 23 '21 at 06:46