Interactive PDFs that launch a new browser tab rather than automatically downloading

I am facing an issue with my web API that is returning a JSReport as an encoded byte array. Despite multiple attempts to read the byte array, I keep encountering either a black screen or an error message indicating "failed to download PDF". Interestingly, when I create a hidden anchor tag and download the PDF, it works perfectly fine. However, my preference is for users to view it directly in their browser rather than downloading it.

WEB API CALL

   var data = LossReportService.GetLossSummary(request);
   var pdf_bytes = LossReportService.GeneratePDFUsingJSReport(data);

   byte[] myBinary = new byte[pdf_bytes.Length];
   pdf_bytes.Read(myBinary, 0, (int)pdf_bytes.Length);
   string base64EncodedPDF = System.Convert.ToBase64String(myBinary);

   var response = Request.CreateResponse(HttpStatusCode.OK, base64EncodedPDF);
   response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
   response.Content.Headers.ContentLength = pdf_bytes.Length;

   return response;                  

Javascript

$.ajax({
    type: "POST",
    url: "/Reporting/GetLossSummary",
    data: { dataObj },
},
success: function (data) {
   if (data != null) {

    //I have tried this
    var file = new Blob([data], { type: 'application/pdf;base64' });
    var fileURL = URL.createObjectURL(file);
    window.open(fileURL, "LossSummaryReport");

    //which gives me a "failed to load PDF document" error

    //and I have tried this, which just renders a blank page
    window.open("data:application/pdf," + encodeURI(data)); 
  }
}
});

Any suggestions on how to resolve this issue would be highly appreciated.

Answer №1

When utilizing jsreport, the typical approach involves using the jsreport browser SDK to efficiently manage the report results and display them in the browser. However, in your scenario where a custom URL is used on the server to render reports, the jsreport browser SDK becomes inadequate. Instead, you are required to handle the report request and response using either jQuery ajax or plain XMLHttpRequest.

Dealing with blob/binary data poses challenges when using jQuery.ajax. You would need to implement a data transport method for $.ajax to facilitate binary data handling.

/**
 *
 * jquery.binarytransport.js
 *
 * @description. jQuery ajax transport designed for making binary data type requests.
 * @version 1.0 
 * @author Henry Algus <<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a7cfc2c9d5dec6cbc0d2d4e7c0cac6cecb89c4c8ca">[email protected]</a>>
 *
 */

// utilize this transport for "binary" data type
$.ajaxTransport("+binary", function(options, originalOptions, jqXHR){
    // validate conditions and support for blob / arraybuffer response type
    if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob))))
    {
        return {
            // create new XMLHttpRequest
            send: function(headers, callback){
        // initialize variables
                var xhr = new XMLHttpRequest(),
        url = options.url,
        type = options.type,
        async = options.async || true,
        // specify blob or arraybuffer. Default is blob
        dataType = options.responseType || "blob",
        data = options.data || null,
        username = options.username || null,
        password = options.password || null;

                xhr.addEventListener('load', function(){
            var data = {};
            data[options.dataType] = xhr.response;
            // execute callback and transmit data
            callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
                });

                xhr.open(type, url, async, username, password);

        // configure custom headers
        for (var i in headers ) {
            xhr.setRequestHeader(i, headers[i] );
        }

                xhr.responseType = dataType;
                xhr.send(data);
            },
            abort: function(){
                jqXHR.abort();
            }
        };
    }
});

However, I lean towards utilizing XMLHttpRequest directly when managing blob data in a request/response as it provides more flexibility for manipulating responses.

function sendReportRequest (dataObj, cb) {
  var xhr = new XMLHttpRequest()
  var data = JSON.stringify(dataObj)

  xhr.open('POST', 'http://url-of-your-server/' + '/Reporting/GetLossSummary', true)
  xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8')
  xhr.responseType = 'arraybuffer'

  xhr.onload = function () {
    if (this.status >= 200 && this.status < 300) {
      var response = xhr.response
      var contentType = xhr.getResponseHeader('Content-Type')
      var dataView = new DataView(response)
      var blob

      try {
        blob = new Blob([dataView], { type: contentType })
        cb(null, blob)
      } catch (e) {
        if (e.name === 'InvalidStateError') {
          var byteArray = new Uint8Array(response)
          blob = new Blob([byteArray.buffer], { type: contentType })
          cb(null, blob)
        } else {
          cb(new Error('Can not parse buffer response'))
        }
      }
    } else {
      var error = new Error('request failed')

      error.status = xhr.status
      error.statusText = xhr.statusText

      cb(error)
    }
  }

  xhr.onerror = function () {
    var error = new Error('request failed')

    error.status = xhr.status
    error.statusText = xhr.statusText

    cb(error)
  }

  xhr.send(data)
}

sendReportRequest(dataObj, function (err, reportBlob) {
  if (err) {
    return console.error(err)
  }

  var reportFileUrl = URL.createObjectURL(reportBlob)

  window.open(reportFileUrl)
})

By implementing this code snippet, you should be able to seamlessly request a PDF file and readily display it in a new browser window.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What could be the reason for the electron defaultPath failing to open the specified directory?

Hi, I'm experiencing difficulties opening the directory path (/home/userxyz/Releases/alpha) using electron. This is what I have attempted: I have a similar path on Ubuntu: /home/userxyz/Releases/alpha When trying to access this path with the fo ...

Real-time File Updates Display with Node.js and Express.js

Seeking guidance on whether there is a Node module available to utilize the Express module for displaying real-time updates in the browser using data from a file. I have a regularly updated .csv file and I am looking to showcase these updates instantly on ...

Ways to extract repeated value from a function?

Currently, I am working with two files. One file contains a script that generates a token, while the other file handles that token. The issue arises with the second script, as it only logs the initial token received and does not update with any new values ...

Error 403 with Google Search Console API: Access Denied

Currently, I am attempting to extract data from the GSC Search Analytics API using Python. Despite diligently following this resource, I have encountered an error that persists despite multiple attempts to remedy it: raise HttpError(resp, content, uri=se ...

The disappearance of the final element in an array after adding a new one using JavaScript

One of the challenges I'm facing in my backbone project involves creating an Add To Cart feature using window.localStorage. Below is my javascript code for the addToCart() function: var cartLS = window.localStorage.getItem("Cart"); var cartObject = ...

Avoid clicking on the HTML element based on the variable's current value

Within my component, I have a clickable div that triggers a function called todo when the div is clicked: <div @click="todo()"></div> In addition, there is a global variable in this component named price. I am looking to make the af ...

Establishing Accessor and Mutator Methods

The variables startStopA... and InitialValueA... that were originally in the component TableFields.vue need to be relocated to the store file index.js. However, upon moving them to the store, an error appears stating that setters are not set. I have extens ...

Switch the ng-bind-html option

Dealing with a string in my scope, I must determine whether I want the HTML escaped or not. A boolean value helps to decide if the HTML should be escaped or left as is. Snippet Check out some of my code examples below: $scope.result = "<b>foo</ ...

Error 404 encountered while attempting to access dist/js/login in Node.JS bootstrap

I currently have a web application running on my local machine. Within an HTML file, I am referencing a script src as /node_modules/bootstrap/dist/js/bootstrap.js. I have configured a route in my Routes.js file to handle this request and serve the appropri ...

Reactivate IntelliJ IDEA's notification for running npm install even if you have previously selected "do not show again" option

One of the great features in Intellij IDEA is that it prompts you with a notification when the package.json has been changed, asking if it should run npm install, or whichever package manager you use. I have enjoyed using this feature for many years. Howe ...

Display temporary image until real image loads within ng-repeat angularjs

I am looking to display a placeholder image while the actual image is being loaded. I have tried using the ng-image-appear plugin. The issue I'm facing is that the placeholder image does not appear for img elements inside ng-repeat, although it works ...

Leveraging the power of React's callback ref in conjunction with a

I'm currently working on updating our Checkbox react component to support the indeterminate state while also making sure it properly forwards refs. The existing checkbox component already uses a callback ref internally to handle the indeterminate prop ...

The responsiveness of Slick Slider's breakpoints is malfunctioning

After implementing a slider using slick slider, I encountered an issue with the width when testing it online and in a normal HTML file. If anyone could assist me in resolving this issue, I would greatly appreciate it. Please inspect the code for both scen ...

What could be causing the incorrect display of updates when my Grails checkbox onclick remote function Ajax call is triggered

Hi, I have a page named taskReminder that renders two templates: one for tasks and another for reminders. The task template includes a checkbox that, when checked, should update the task list. Everything is functioning correctly, but there seems to be an i ...

Implementing Isotope layout in Reactjs with data-attributes for filtering and sorting content

I am currently working on optimizing the isotope handler within a react component. My goal is to implement filter options such as category[metal] or category[transition], as well as combo filters like category[metal, transition]. Here is the sandbox for t ...

I've been struggling with this javascript error for three days, how can I finally resolve it?

Currently developing a website using react js, but encountering an error every time I try to push to my github repository. Run npm run lint npm run lint shell: /bin/bash -e {0} <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail= ...

Using console.log() within a method while chaining in JavaScript/jQuery

I've been experimenting with developing jQuery plugins and I'm interested in chaining methods. The jQuery tutorial (found here: https://learn.jquery.com/plugins/basic-plugin-creation/) mentions that you can chain methods by adding return this; at ...

Attempting to determine income in JavaScript with the inclusion of two distinct rates

Trying to come up with a salary calculation for different rates within the same timeframe is proving to be quite challenging. For instance, between 10:00-15:00 the rate is $20 per hour and from 15:00 onwards it drops to $15 per hour. Check out the entire ...

Node.js powered file uploading on the Heroku platform

After attempting to upload a file to Heroku using https://www.npmjs.com/package/express-fileupload, I encountered an error. It worked fine on my PC, but on Heroku, I received the following error message: {"errno":-2,"code":"ENOENT","syscall":"open","path" ...

The function `collect` cannot be found for the object #<Page:0x007f4f200a9350

Seeking assistance with an error I've encountered. As a novice, I'm still navigating my way through this, so any guidance on how to resolve it would be greatly appreciated. Attached is the portion of code that is triggering the error: 3: <%= ...