How to receive a pdf file via ajax?

3

I am using this method to return a PDF file. It works normal if I call this action directly via URL:

    public ActionResult GerarProva(int idEpo, int numero, bool existeProvaGerada)
    {
        try
        {
            var relatorioBll = new RelatorioBll();
            var dados = relatorioBll.ObterQuestoesProva(numero, idEpo, existeProvaGerada);

            _dadosGeracaoProva = dados;

            System.Web.HttpContext.Current.Response.ContentType = "application/pdf";
            System.Web.HttpContext.Current.Response.AddHeader("content-disposition",
                "attachment;filename=" + ControllerContext.RouteData.Values["action"] + DateTime.Now.ToFileTime() +
                ".pdf");
            System.Web.HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);

            Stream pdfStream = System.Web.HttpContext.Current.Response.OutputStream;
            GerarPdf<ProvaItem>.GerarProva(pdfStream, dados.ToList());

            System.Web.HttpContext.Current.Response.Write(dados);
            System.Web.HttpContext.Current.Response.End();

            return File(System.Web.HttpContext.Current.Response.OutputStream, "application/pdf");
        }
        catch (Exception ex)
        {
            Danger("Erro: " + ex.Message);
        }

        return RedirectToAction("Index");
    }

But I would like to download the file through ajax. I need to perform a javascript action within the "success":

            $.ajax({
                url: link,
                success: function (data) {
                    var blob = new Blob([data]);
                    var link = document.createElement('a');
                    link.href = window.URL.createObjectURL(blob);
                    link.download = "Preview.pdf";
                    link.click();
                },
                error: function (err, er, e) {
                    if (err.responseText.indexOf("encontradas") === -1) {
                        alert("Erro.");
                    } else {
                        alert("Erro: Não foram encontradas questões válidas para a geração da prova.");
                    }
                }
            });

I tried this code, but the pdf comes with blank pages. One of my assumptions is that my server side method is not returning the correct type ...

    
asked by anonymous 18.08.2015 / 18:51

3 answers

1

Organize as follows:

Create your AJAX function by getting a function to execute within the success:

function someAjax(functionToExecute){
    $.ajax({
        type: 'post',
        url: 'www.site.com',
        success: function (response) {
            functionToExecute(response);
        },
        dataType: 'json',
        global: false
    });
}

Function to execute within success:

displayFile(file){
    // Faz algo
}

Function that calls the function that encapsulates the AJAX call. Pass the function name as a parameter without quotes.

function (){
    someAjax(displayFile);
}
    
18.08.2015 / 19:43
1

The question asks for a solution via ajax, however, the intention is to perform an action at the end of the download so I present a simple solution:

Complete example:

    <html>
    <head>
    <script src="js/jquery/jquery-1.11.0.min.js"></script>
    <script type="text/javascript">
    $().ready(function() {

    $('#target').load(function(){
        /*
        Aqui, o download foi completado. (o carregamento do iframe)
        */
        foo();
    });

    $('#file_download').click(function() {
        $("#target").attr("src",$(this).attr('href'));
    });

});

function foo()
{
    console.log('loaded');
}
    </script>
    </head>
    <body>

    <a id="file_download" download="arquivo.pdf" href="http://localhost/arquivo.pdf" > Download PDF </a><br />


    <iframe id="target" src="" width="50" height="10" border="1"></iframe>

    </body>
    </html>

The technique is to download normally, triggered by the <a> element, where the download attribute indicates that the link should be downloaded.

We've added a listen for the click event on the <a> element. The idea is that at the time of the click, the download will start. In this exact instance, a iframe will be loaded with the same link.

The utility of iframe in this technique is due to the load() method that returns the time when iframe loads.

The logic in this is, the same file is being downloaded by the element <a> and by iframe .

Both will terminate dowload at the same time, and the desired action is performed at that time.

It may happen that dowload and loading do not complete if the browser displays a dialog box for the user to confirm execution. At this point, regardless of whether the user accepts or not, the iframe will continue to load.

To make the action more discreet, hide the iframe with $('#target').hide() .

This may seem like a perfect solution, however, the download attribute is not supported by IE and Safari.

link

If you want to run in a controlled environment, where the user should use Chrome, Firefox or Opera, it can be a good solution.

Despite this small inconvenience with the download attribute, you can still create implementations for the other browsers.

    
27.08.2015 / 22:53
0

look, since the expected response is a blob, then it is interesting to make an ajax request through the XMLHttpRequest and set the responseType to blob.

var uploadFile = document.getElementById("uploadFile");

uploadFile.addEventListener("change", function (event) {
  var link = URL.createObjectURL(event.target.files[0]);
  
  var xmlHttp = new XMLHttpRequest();  
  xmlHttp.open("GET", link, true);
  xmlHttp.responseType = "blob";
  xmlHttp.onreadystatechange = function (e) {
    if (xmlHttp.readyState == 4 && (xmlHttp.status == 200 || xmlHttp.status == 0)) {
      var link = document.createElement('a');
      link.href = URL.createObjectURL(xmlHttp.response);
      link.download = "Preview.pdf";
      link.click();
    }
  }    
  xmlHttp.send();
})
<div>
  <p>será feita uma coisa do arquivo selecionado e o mesmo será baixando por AJAX.</p>
  <input id="uploadFile" type="file" />
</div>
    
27.08.2015 / 21:49