I'm new to Angular, so I'm having some issues regarding async functions. This is my code, at this moment:
generateMovementPlanPDF(data) {
this.movementPlanService
.getMovementPlanPDF(data.movementPlan.id)
.subscribe((data) => {
this.openExtract(
this.sanitizer.bypassSecurityTrustResourceUrl(
URL.createObjectURL((b64toBlob as any)(data, 'application/pdf'))
)
);
});
}
openExtract(path): void {
this.dialog.open(ExtractInvoiceComponent, {
width: '100%',
height: '100%',
data: { path },
header: 'Plano de Movimentação - PDF',
});
}
This is my service request:
getMovementPlanPDF(movementId: number): Observable<any> {
return this.http.get(`${this.apiUrl}/${movementId}/create-pdf`).pipe(map((response: any) => response.data.printPDF));
}
From what I've learned the .subscribe() would make my sync functions wait for my request correct? But when I test this, these sync functions are not waiting at all, and the PDF is blank because there's no base64 to be rendered yet...
What am I missing?
CodePudding user response:
If I understand correctly, you expect the subscribe method to "make my sync functions wait for my request". However, .subscribe()
doesn't do that.
The subscribe method comes from the rxjs library. As soon as you use .subscribe()
, the observable returned by the http.get request in your service starts to emit data. The subscribe method invokes the observable, right there where you use it, and shows/emits data.
Observables can be synchronous and asynchronous but in any case .subscribe()
doesn't change them.
It seems this was confusing, so here are two reads:
- Think of Observables as newsletters
- Read more about subscriptions on rxjs
CodePudding user response:
My suggestion is to subscribe (whenever it is possible) directly in the template.
I see as well that you are using angular material components (whitch i like it a lot), then I would use it at the most. You can pass a "data" argument to the open() method, and there you might pass the id of the document.
In the DIALOG component, you can use this on ngOnInit():
this.pdf$ = this.movementPlanService.getMovementPlanPDF(data.movementPlan.id);
(this will NOT subscribe to the data yet, just creates the observable to be subscribed)
then, in the template you do this:
<ng-container *ngIf="pdf$ | async | CUSTOM_PIPE as DATA">
<!-- you can use the "DATA" inside this tag as you wish now, preview here, put a button to download it -->
</ng-container>
The goodpart of this approach is that, when the dialog component closes, the subscription will be automatically erased and the memory will be cleaned
The hard part is that the function you have used to sanitize must be inside the custom pipe you shall create. This might be a litte confusing when starting in angular, but is the best approach (the one I would do at least)
I reccomend a youtube channel where I learned a lot Angular tricks: https://fireship.io/
I hope it helps