0

In my project, I'm using angular6 with Springboot backend. So what I'm trying to do is popup the save dialog using this controller java class,

@RequestMapping(value = "/getGeneratedLetter/{userId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public void genarateLetter(@PathVariable("userId") Integer userId, HttpServletResponse response) {
        System.out.println(userId);
        letterTypeService.genarateLetter(userId);
        try {
            // get Letter.docx from file path
            InputStream is = new FileInputStream("Letter.docx");
            response.setHeader("Content-Disposition", "attachment; filename = Letter.docx");
            IOUtils.copy(is, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception ex) {
            throw new RuntimeException("IOError in " + ex);
        }
    }

Note: in my letterTypeService java class the letter will be generated correctly.

And finally, I'm catching the response in my angular front-end in my component,

getGenaratedLetterTemplate(letter) {
  this.data.getGenaratedLetterTemplate(letter.letterId).subscribe(response => {
    this.getBasicDataFromBackend();
    saveAs(response,  letter.fullName + '_' + letter.letterTypeName + '.docx');
    console.log(response);
  }, error => {
    console.log(error);
  });
}

In above function responce will not catch since the result is

error massage: "OK"

It's confusing because it displayed just "OK" there are not any specific error details. Additionally in my service in frontend successfully send get request and in-network tab in chrome dev tools displays "status code:200" enter image description here

Further investigation When I copy and paste my get request URL in new browser window the letter download popup will be displayed successfully and when I click the save button the letter will download successfully.

So what could be the issue here?

INDRAJITH EKANAYAKE
  • 3,894
  • 11
  • 41
  • 63

1 Answers1

2

As M. Deinum indicated. AJAX does the GET request transparently, so there will be no popup. You could build a link in your client, which you can click (same as if you copied the link into a new browser). E.g. I did something similar for an app of mine, where I have the following in my template:

 <a [href]="yourUrl" class="btn btn-primary" role="button">
     <i class="fa fa-calendar"></i> <!-- or whatever you want to display -->
 </a>

And the yourUrl then would be the url to your backend. It should popup a download dialogue (I did not test it for files coming from the backend, but I think this should work).

Edit: This Answer suggests that you cannot download files directly with AJAX, primarily for security reasons. This codepen shows how to do it with Javascript, but it basically does the same thing: It creates an anchor tag, puts the data into an objectURL, adds it to the DOM, clicks it and removes itself again, so in the end you see a popup. The download attribute in the pen only works for same-origin requests, but since you set a Content-Disposition header, you could also leave it out (here is some more information about this). For this to work with Angular, you could basically take the code in the success: clause and copy it to your http call (I'd suggest replacing the vars with consts). It's not clean Angular however, because you directly interact with the DOM and if you use server-side rendering, you'd have to check for this. And it can cause memory leaks.

thomi
  • 1,603
  • 1
  • 24
  • 31