Onur Arı
Onur Arı

Reputation: 512

Using Angular 2 to generate a Docx Files

I am using angular2 and I want to generate a docx file using an object. I want my docx file to contain footers, headers, tables etc. The best solution i can come up with is first creating an HTML file, then converting it to docx file. But this does not seem right. Is there an easier and more convenient way to do what I want to do? Here is the method I use:

exportAsDoc() {

const preHtml = '<html xmlns:o=\'urn:schemas-microsoft-com:office:office\' ' + '' +
        ' xmlns:w=\'urn:schemas-microsoft-com:office:word\' xmlns=\'http://www.w3.org/TR/REC-html40\'><head><meta charset=\'utf-8\'>' +
        '<title>Export HTML To Doc</title></head><body>';
const postHtml = '</body></html>';

let innerHtml = '';
// Specify file name
const filename = this.respSheet.title + '.doc';
const respSheetKpis = this.respSheet.sheet_kpis;
respSheetKpis.forEach(x => {
  const footer = '<p style="text-align: center">' + x.kpi.name + ' - ' + x.kpiValue + '</p>';
  innerHtml += footer;
  x.sheet_kpi_dimensions.forEach(dimension => {
    if (dimension.dimension !== undefined) innerHtml += dimension.dimension.name;
    let table = '<table>\n' +
            '  <tr>\n' +
            '    <th>Istatistik adi</th>\n' +
            '    <th>Degeri</th> \n' +
            '  </tr>\n';
    const data = dimension.data;
    if (data !== undefined) {
      for ( let i = 0 ; i < data.length ; i ++ ) {
        table += ' <tr>\n' +
                '    <th>' + data[ i ].title + '</th>\n' +
                '    <th>' + data[ i ].value + '</th> \n' +
                '  </tr>\n';
      }
      table += '</table>';
      innerHtml += table;
    }
  })
});
const html = preHtml + innerHtml + postHtml;

const blob = new Blob(['\ufeff', html], {
  type: 'application/msword'
});

// Specify link url
const url = 'data:application/vnd.ms-word;charset=utf-8,' + encodeURIComponent(html);

// Create download link element
const downloadLink = document.createElement('a');

document.body.appendChild(downloadLink);

if (navigator.msSaveOrOpenBlob ) {
  navigator.msSaveOrOpenBlob(blob, filename);
} else {
  // Create a link to the file
  downloadLink.href = url;

  // Setting the file name
  downloadLink.download = filename;

  // triggering the function
  downloadLink.click();
}

document.body.removeChild(downloadLink);

}

Upvotes: 3

Views: 18887

Answers (2)

Asif Karim Bherani
Asif Karim Bherani

Reputation: 1083

Too late for the reply but this might be helpful for someone else. One way to implement this is using the docx.js

I have added simple example and link to example and documentation

https://stackblitz.com/edit/angular-afvxtz

https://docx.js.org/#/

TS file:

import { Component } from '@angular/core';
import { Packer } from 'docx';
import { saveAs } from 'file-saver/FileSaver';

import { DocumentCreator } from './cv-generator';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name = 'Angular';

  public download(): void {
    const documentCreator = new DocumentCreator();
    const doc = documentCreator.create();
    doc.createParagraph("Test heading1, bold and italicized").heading1();
    doc.createParagraph("Some simple content");
    const packer = new Packer();

    packer.toBlob(doc).then(blob => {
      console.log(blob);
      saveAs(blob, "example.docx");
      console.log("Document created successfully");
    });
  }
}

cv-generator.ts file:

import { Document, Paragraph, Packer, TextRun } from 'docx';


export class DocumentCreator {
  create() {
    const title = 'EXECUTIVE SUMMARY';
    const document = new Document();
    document.addParagraph(new Paragraph(title).title());
    document.addParagraph(this.createHeading('Exception Overview'));
    return document;
  }
  createHeading(text) {
    return new Paragraph(text).heading1().thematicBreak();
  }
}

HTML:

<button class="em-primary-button" (click)="download()">Download file</button>

Upvotes: 7

in my opinion the simplest tool to work for generating documents on the front end is Docx.js. I think it can help you solve your problem.

In this project you generate a simple HTML using a Javascript (or typescript) code, and save as a Docx file. Something like that:

<script>
    function exportAsDoc() {
        var content = '<!DOCTYPE html>';

        var items = [
            {col1: "foo", col2: "bar"}
        ];

        content += "<html><body><table>";
        content += "<tr>";
        content += "<th>col1</th><th>col2</th>";
        content += "</tr>";

        for (var i=0; i<items.length; i++) {
            content += "<tr>";
            content += "<td>" + items[i].col1 + "</td>";
            content += "<td>" + items[i].col2 + "</td>";
            content += "</tr>";
        }
        content += "</table></body></html>";

        var converted = htmlDocx.asBlob(content, {orientation: "landscape"});
        console.log(converted);
        saveAs(converted, 'test.docx');
    }
</script>

On the project website you have a complete example using an online editor. Just follow the example and adapt to your project

http://evidenceprime.github.io/html-docx-js/

Upvotes: 1

Related Questions