Reputation: 171
I have two components. Billing component(User type the item details) and billpage component (Pdf page is designed and pdf is generated).
The item details from(billing.ts) are passed through service (pdfcontent.service.ts) to billpage component(billpage.ts).
Below I shared the screen shot. Everything is working fine except one major issue. Here when I submit the button pdf is generated from billpage component. But the design of pdf page(highlighted in yellow square ) is appearing in the billing page. But I don't need to show this in the view. I do the below steps to avoid but none of them are giving good result.
<app-billpage style="display:none"></app-billpage>
Pdf is not generated when display none property give.<app-billpage style="visibility:hidden"></app-billpage>
Empty pdf is generated.<app-billpage></app-billpage>
pdf is not generated.billing.component.html
<form [formGroup]="productFormarray">
.....
....
...
</form>
<app-billpage></app-billpage>
billing.component.ts
onSubmit() {
this.billcontent=this.productFormarray.value;
this.pdfService.updatePdfContent(this.billcontent);
}
pdfcontent.services.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject, Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class PdfcontentService {
constructor() { }
public pdfContentSource = new BehaviorSubject<any>("");
pdfContent$ = this.pdfContentSource.asObservable();
updatePdfContent(content: any) {
this.pdfContentSource.next(content);
}
}
billpage.component.html
<div id="billpagecontent" class="p-4">
<p>Customer Name: {{billpagecontent.customername}}</p>
<p>Contact Number: </p>
<p>Bill No</p>
<table class="table" style="margin-top: 20px; width:fit-content;">
<thead>
<tr>
<td style="width:40%">
Product Name
</td>
<td style="width:15%; text-align: right;">
Quantity
</td>
<td style="width:15%; text-align: right;">
Price
</td>
<td style="width:15%; text-align: right;">
Gst
</td>
</tr>
</thead>
<tr *ngFor="let product of billpagecontent.productdetails">
<td>{{product.productname}}</td>
<td style="text-align: right;">{{product.quantit}}</td>
<td style="text-align: right;">{{product.price}}</td>
<td style="text-align: right;">{{product.gst}}</td>
</tr>
<tr>
<td></td>
<td style="text-align: right;"><b>Total</b></td>
<td style="text-align: right;">{{billpagecontent.totalprice}}</td>
<td style="text-align: right;">{{billpagecontent.totalgst}}</td>
</tr>
<tr>
<td></td>
<td style="text-align: right;"><b>Total Bill</b></td>
<td style="text-align: right;">{{billpagecontent.overalltotal}}</td>
<td style="text-align: right;"></td>
</tr>
</table>
</div>
billpage.component.ts
import { Component, OnInit } from '@angular/core';
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
import { PdfcontentService } from '../services/pdfcontent.service';
@Component({
selector: 'app-billpage',
templateUrl: './billpage.component.html',
styleUrls: ['./billpage.component.css']
})
export class BillpageComponent implements OnInit {
billpagecontent: any = {};
constructor(public pdfService: PdfcontentService) {
}
ngOnInit(): void {
this.pdfService.pdfContent$.subscribe(content => {
if (content) {
this.billpagecontent = content;
let pdfcontent = document.getElementById('billpagecontent');
setTimeout(() => {
this.convetToPDF(pdfcontent);
}, 3000);
}
});
}
public convetToPDF(bcontent: any) {
var data = bcontent as HTMLCanvasElement;
html2canvas(data).then(canvas => {
// Few necessary setting options
var imgWidth = 208;
var pageHeight = 295;
var imgHeight = canvas.height * imgWidth / canvas.width;
var heightLeft = imgHeight;
const contentDataURL = canvas.toDataURL('image/png')
let pdf = new jsPDF('p', 'mm', 'a4'); // A4 size page of PDF
var position = 0;
pdf.addImage(contentDataURL, 'PNG', 0, position, imgWidth, imgHeight)
pdf.save('new-file.pdf'); // Generated PDF
});
}
}
Please someone help to solve this.
How to initiate another component without placing the template of that component. (<app-billpage></app-billpage>
)
Upvotes: 2
Views: 46
Reputation: 11
You can create additional variable inside the component to hide the template until the download is done, although you may see a small tick of the content appearing for a short period of time.
It may be necessary to use Angular detectorChange to wait for the ngIf to load before download.
<div id="billpagecontent" class="p-4" *ngIf="showContent">
<p>Customer Name: {{billpagecontent.customername}}</p>
<p>Contact Number: </p>
<p>Bill No</p>
<table class="table" style="margin-top: 20px; width:fit-content;">
<thead>
<tr>
<td style="width:40%">
Product Name
</td>
<td style="width:15%; text-align: right;">
Quantity
</td>
<td style="width:15%; text-align: right;">
Price
</td>
<td style="width:15%; text-align: right;">
Gst
</td>
</tr>
</thead>
<tr *ngFor="let product of billpagecontent.productdetails">
<td>{{product.productname}}</td>
<td style="text-align: right;">{{product.quantit}}</td>
<td style="text-align: right;">{{product.price}}</td>
<td style="text-align: right;">{{product.gst}}</td>
</tr>
<tr>
<td></td>
<td style="text-align: right;"><b>Total</b></td>
<td style="text-align: right;">{{billpagecontent.totalprice}}</td>
<td style="text-align: right;">{{billpagecontent.totalgst}}</td>
</tr>
<tr>
<td></td>
<td style="text-align: right;"><b>Total Bill</b></td>
<td style="text-align: right;">{{billpagecontent.overalltotal}}</td>
<td style="text-align: right;"></td>
</tr>
</table>
</div>
billpage.component.ts
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
import { PdfcontentService } from '../services/pdfcontent.service';
@Component({
selector: 'app-billpage',
templateUrl: './billpage.component.html',
styleUrls: ['./billpage.component.css']
})
export class BillpageComponent implements OnInit {
billpagecontent: any = {};
showContent: boolean = false;
constructor(public pdfService: PdfcontentService, private detectorChange: ChangeDetectorRef) {
}
ngOnInit(): void {
this.pdfService.pdfContent$.subscribe(content => {
if (content) {
this.billpagecontent = content;
let pdfcontent = document.getElementById('billpagecontent');
setTimeout(() => {
this.convetToPDF(pdfcontent);
}, 3000);
}
});
}
public convetToPDF(bcontent: any) {
showContent = true;
this.detectorChange.detectChanges();
var data = bcontent as HTMLCanvasElement;
html2canvas(data).then(canvas => {
// Few necessary setting options
var imgWidth = 208;
var pageHeight = 295;
var imgHeight = canvas.height * imgWidth / canvas.width;
var heightLeft = imgHeight;
const contentDataURL = canvas.toDataURL('image/png')
let pdf = new jsPDF('p', 'mm', 'a4'); // A4 size page of PDF
var position = 0;
pdf.addImage(contentDataURL, 'PNG', 0, position, imgWidth, imgHeight)
pdf.save('new-file.pdf'); // Generated PDF
showContent = false;
});
}
}
If you want more control over the content printend and how it looks maybe you can create a button calling the window.print()
. With this strategy you can have overwrite CSS styles for the PDF using the @media print
CSS media query. Furthermore, the user can use the same print dialog to save as PDF and print it and no external dependencies are needed.
Upvotes: 1