Search code examples
angularjspdfjspdf-autotable

JsPDF Autotable adding Images to column gives error: Property 'getElementsByTagName' does not exist


I'm trying to add an image from AWS S3 bucket using its url, with the format of the data looking like:

[{
  netValue: 13702.5,
  prodCode: "UPP",
  prodDesc: "Privacy Panel",
  prodImg: "https://url/images/UPP02.png",
  prodQty: 20,
  unitPrice: 870
}]

With the table in my html file looking like:


<table class="table table-hover table-responsive-xxl table-bordered" id="prodTable" #prodTable>
    <thead>
        <tr class="table-reflow">
            <th>S. N</th>
            <th>Product Code</th>
            <th>Description</th>
            <th>Image</th>
            <th>Qty</th>      
            <th>Price</th>      
            <th>Amount</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let prod of prodDetailsArr; let i = index">
            <td>{{ i+1 }}</td>
            <td>{{ prod.prodCode }}</td>
            <td>{{ prod.prodDesc }}</td>
            <td><img [src]="prod.prodImg"></td>
            <td>{{ prod.prodQty }}</td>
            <td>{{ prod.unitPrice }}</td>
            <td>{{ prod.netValue }}</td>
        </tr>
    </tbody>
</table>

With the table being displayed without its image in the PDF file, I tried using the code below to access it, but I get the following errors that stop compiling, even though console.log(td) gives the proper img and its src:

autoTable(doc, { 
      html: '#prodTable',
      startY: 200,                    
      theme: 'plain',
      tableLineColor: [0, 0, 0],
      tableLineWidth: 0.5,
      margin: {
        left: 5,
        right: 7
      },
      didDrawCell: function(data) {
        if (data.column.index === 3 && data.cell.section === 'body') {
          var td = data.cell.raw;
          console.log(td)
          var img = td.getElementsByTagName('img')[0];
          var dim = data.cell.height - data.cell.padding('vertical');
          doc.addImage(img.src, data.cell.x,  data.cell.y, dim, dim);         
        }
      }
    })

Property 'getElementsByTagName' does not exist on type 'HTMLTableCellElement | CellInput'. Property 'getElementsByTagName' does not exist on type 'string'.

And when I try to save pdf, I get:

zone-evergreen.js:2981 Access to XMLHttpRequest at 'https://url/images/UPP02.png' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

ERROR Error: addImage does not support files of type 'UNKNOWN', please ensure that a plugin for 'UNKNOWN' support is added. at Object.P (jspdf.es.min.js:86:93253) at push../node_modules/jspdf/dist/jspdf.es.min.js.e.addImage

Here is a stackblitz illustrating the problem When I try to insert image into the table, I get an error stating "Incomplete or corrupt PNG File". I'm using jspdf: ^2.5.1, and jspdf-autotable: ^3.5.31, alongside angular 8.

Where exactly am I going wrong?


Solution

  • For the 1st issue, the td variable is HTMLTableCellElement | CellInput type.

    The getElementsByTagName() is only available from the Element type and HTMLTableCellElement inherits the Element type.

    Thus you have to cast the td as HTMLTableCellElement.

    Either

    var img = (td as HTMLTableCellElement).getElementsByTagName('img')[0];
    

    or

    var td= data.cell.raw as HTMLTableCellElement;
    

    For the 2nd issue, it seems the problem came from the AWS S3 Bucket which implements the CORS and blocks your Angular app from accessing as it is not whitelisted.

    You should configure the CORS rule to allow (whitelist) the Angular application IP (if it is exposed to the public) in AllowedOrigins. Or enforce the wildcard (*) rule for AllowedOrigins but you may bear the risk as this will allow all origins. You may refer to CORS configuration for AWS.