I have a situation where I have a list of items each represent a file. All these files can be fetched from a backend as blobs. I want to have links in the frontend when user clicks should be able to download the file for him/her.
The solution I have pre downloads the file and creates a SafeResourceUrl
.
But, my problem is since I now have to show a list of links pre downloading all of them initially is a waste. I need to make it such that when I click the link the network call will go and fetch the file and then the download popup should be opened.
here is the code I have for predownloading
component
import { Component, OnInit } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { AppService } from './app.service';
import { HttpResponse } from '@angular/common/http';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent implements OnInit {
url?: SafeResourceUrl;
stream: ArrayBuffer | null = null;
fileName: string = 'test.pdf';
constructor(
private appService: AppService,
private sanitizer: DomSanitizer
) {}
ngOnInit(): void {
this.appService.fetchPdf().subscribe((response: HttpResponse<Blob>) => {
const blob = response.body!;
blob.arrayBuffer().then((res) => {
this.stream = res;
});
this.createLink(blob);
});
}
async createLink(blob: Blob): Promise<void> {
const buffer = await blob.arrayBuffer();
if (buffer.byteLength) {
const uint = new Uint8Array(buffer);
let bin = '';
for (let i = 0; i < uint.byteLength; i++) {
bin += String.fromCharCode(uint[i]);
}
const base64 = window.btoa(bin);
const url = `data:${blob.type};base64,${base64}`;
this.url = this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
}
service
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class AppService {
private pdfUrl =
'https://s28.q4cdn.com/392171258/files/doc_downloads/test.pdf';
constructor(private http: HttpClient) {}
fetchPdf(): Observable<HttpResponse<Blob>> {
return this.http.get(this.pdfUrl, {
observe: 'response',
responseType: 'blob',
});
}
}
html
<h1>download test</h1>
<div *ngIf="url">
<a [href]="url" [download]="fileName">{{ fileName }}</a>
</div>