44

We have an Angular application that gets some input parameters and sends them to the back end where they get processed. The processing result is a pdf file that we want to open in a new tab.

The code doing this looks similar with below:

myService.getDocument(document)
  .then(function(response) {
    if (response.error) {
      // Error handling goes here
    } else {
      var file = new BLob([response.data), {type: 'application/pdf'});
      var fileURL = URL.createObjectURL(file);
      $window.open(fileURL, '_blank_');
    }
  });

Everything works fine but the URL in the browser shows some random generated string as below:

blob:http://localhost:3000/85cad96e-e44e-a1f9-db97a96ed3fe

Obviously this does not look very good to the end user and we would prefer to display something which is meaningful to the user, say something like below:

blob:ftp://localhost:3000/my_document_name_or_whatever

I am new to JS, new to Angular, new to HTML and hope my question does not sounds very naive.

Thank you in advance for your inputs.

Soviut
  • 88,194
  • 49
  • 192
  • 260
Julian
  • 3,678
  • 7
  • 40
  • 72

7 Answers7

48

Short answer, You can't.

This is an address that points to the browser's memory, where it has stored your blob, or a pointer to the original file in case of user uploaded file through the input type=file.

This is somehow by design. You can create multiple of these blobURLs from the same Blob. If they were to use a filename as URI, you couldn't.

Theoretically, it should be possible for you to dynamically create a page that would redirect to the BlobURI, and you could name this redirection page as you which. But this is just theory, I never tried to do it myself.

A rough proof of concept can be seen in this plunker, obviously, you'll need to generate blobRename.html dynamically, and change its name to the one you want, and also force it's content-header so that the browser thinks it's an html page if you want to get rid of the .html. Also note that it doesn't seem to work with pdf files, which need browser plugins to trigger in, but with some more work, it may be possible to hack something around.

But anyway, I would just let the random url, your users will get more and more used to it as more and more web apps do use this great API.

Kaiido
  • 123,334
  • 13
  • 219
  • 285
28

Inside else condictional code above, insert this following code below:

var file = new Blob([response.data], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);

// create <a> tag dinamically
var fileLink = document.createElement('a');
fileLink.href = fileURL;

// it forces the name of the downloaded file
fileLink.download = 'pdf_name';

// triggers the click event
fileLink.click();
Yurii Holskyi
  • 878
  • 1
  • 13
  • 28
Marcelo Vinicius
  • 805
  • 10
  • 8
2

I was looking for the same and actually you can add a download attribute for the link and that would make the trick on Chrome, I didn't tried in IE so far.

<a href="urlBlobData" download="fileTest.csv">Your file</a>

and this is an example with Angular 5

<a #link *ngIf="urlBlobData" [href]="urlData" target="_blank" rel="noopener" download="fileTest.csv">Your file</a>

Hope that work for you as well.

  • How to provide ngIf and download attribute's values? I am getting binary format file in an api response, `target='_blank'` in html its still not working, I tried removing download attribute too, what else is needed? – Pinka Apr 02 '21 at 13:20
0

There's another possible solution that can be explored but it has it's own issues. You can actually store your blob url in the browser cookie storage and then retrieve it from another tab and when you create the shared worker it will connect to the same worker. The caveat here is that your blob can disappear while your cookie value is still set so when a new worker gets initialized it will silently fail. There may be ways to mitigate this if you tested somehow to see if the worker script was running successfully and if it's not, erase the cookie and recreate the blob. However there doesn't seem to be a reliable way to know if workers are running from the main thread so this would be tricky, but I suspect doable if you use some delays/timeouts and wait for an echo from the worker for example.

Dre
  • 1,985
  • 16
  • 13
-2

Taken from How to set a file name using window.open

Granted this is downloading the file not opening in another tab.

var downloadLink = document.createElement("a");
downloadLink.href = myBlob;
downloadLink.download = "myFile.pdf";

document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
Eric Soyke
  • 1,073
  • 1
  • 15
  • 30
-2

You can add/pass file name by adding below, however it will download the file instead of opening it in new tab, but at least user will get a properly named file,

//import and inject Renderer2
import { Renderer2 } from '@angular/core';

let downloadLink = this.renderer.createElement('a');

//this converts binary data to a pdf
downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: 'application/pdf' }));

//you can pass filename here
   downloadLink.setAttribute('download', filename); 
   document.body.appendChild(downloadLink);
   downloadLink.click();
Pinka
  • 165
  • 1
  • 3
  • 12
  • Just curious, why is this answer given negative rating? This worked for me, after trying lots of different things for whole two days. It might be helpful for a person facing same scenario as me. – Pinka May 05 '21 at 04:29
  • 1
    What is downloadLink, and how does it relate to the original question? – Steve Schmitt May 18 '21 at 22:47
  • @Pinka it gets downvoted because it doesn't solve the problem. Your solution downloads the document (I assume PDF) instead of showing it in a new tab (with ultimately the correct PDF name). – DanKas Jul 26 '21 at 12:08
  • @Dankas Yes, it does download the pdf instead of opening it in new tab, but as mentioned, I just posted the solution of how we can pass/set the name of the file as the original question had that issue of not being able to set name. It is just a workaround to set name. Sorry, I'll update my answer to inform same. – Pinka Jul 26 '21 at 13:02
  • @DanKas Have you found the solution for the same? – Prashant Agrawal Jul 29 '21 at 10:31
  • 2
    @Pinka also your answer is a little late. Other answers already mentioned this solution years ago – Casper Mar 11 '22 at 09:52
-3

You can simply add a setTimeout to change the page title after the blob has been loaded in the new tab like this -

newTab.location.href = URL.createObjectURL(blob); 
setTimeout(function() {
    newTab.document.title = blob.name;
}, 10);
Lior Cohen
  • 5,570
  • 2
  • 14
  • 30