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

Evaluating different attributes within a single entity

I was attempting to write some code that checks if two individuals share the same birthday. Person "a" and person "b" do not have the same birthday, yet the console output shows: a was born on day 1 a has the same birthday as a a has the same birthday as ...

The JavaScript for loop using .appendChild() is inserting the values of the final object, represented as [object object], into the HTML document

$(document).ready(function () { GetDetails(); }); function GetDetails() { let albumlist = document.getElementById("album-list"); $.ajax({ url: '/Store/browseajax', type: 'GET', data: { id: '@ ...

Implementing JavaScript to showcase a list extracted from an API dataset

I'm currently undertaking a project where I am integrating an API from a specific website onto my own webpage. { "data": [{ "truckplanNo":"TCTTV___0D010013", "truckplanType":"COLLECTION", " ...

Tips on changing an image with a button click

I am currently working on a project where I have a div tag containing an image that is selected randomly from different arrays based on topics. However, I am facing some challenges in making the image change when the "go" button is clicked. I want the if ...

How can I ensure that Mongoose is case sensitive?

Currently, our authentication system is case sensitive for the email input. However, I would like to make it case insensitive. Here is the function in question: Auth.authenticate({ email, password }) Auth represents a mongoose Model that stores users in ...

Is it possible to easily extract all values associated with a particular key in a nested JSON using JavaScript?

I have a JSON structure that looks like this: [ { cells: [ { id: "1", cellType: 3, widget: { id: 1, description: "myDesc"} }, { id: "2", cellType: 4, widget: { id: 2, description: "myDesc2"} } ] }, { cells: [ { id: "3", c ...

Date input using manual typing format

I've implemented the ng-pick-datetime package for handling date selection and display. By using dateTimeAdapter.setLocale('en-IN') in the constructor, I have successfully changed the date format to DD/MM/YYYY. However, I'm facing an iss ...

The server is unable to process the request with parameters for the specified URL

I've been encountering an error every time I try to post something. articlesRouter.post('articles/:target', async (req, res) => { const target = req.params.target.replaceAll("_", " ") const article = await Arti ...

In Ruby on Rails, Disqus Ajax is failing to associate different threads with different posts

In my Rails application, I have integrated Disqus Universal Code for the comment function. I am utilizing ajax remote => true function to display the content of my posts. Below is the Disqus code snippet: <div id="disqus_thread"></div> ...

Collect hyperlinks within an Ajax-loaded webpage

If you visit the following page: and navigate to the screws section, you'll notice that there are no individual A tags for each item in the list. However, by right-clicking on an item and checking your browser tools, you'll see that the A tag ap ...

How can I incorporate multiple JSX files into plain HTML without using npm?

I have a question regarding importing JSX files in an HTML file without using npm and directly running it with LiveServer. I have two files, index.js and app.jsx, that I want to connect within my index.html script. How can I achieve this? Code: index.html ...

AJAX Enabled WordPress Site with Challenging URL Configuration

The challenge of implementing AJAX on this WordPress theme has proven to be quite difficult. Despite the efforts of the developer, the issue remains unresolved. For this site to run smoothly, you must enter the complete URL "". Simply typing in the .com a ...

Determine whether the response originates from Express or Fastify

Is there a method to identify whether the "res" object in NodeJS, built with Javascript, corresponds to an Express or Fastify response? ...

Exploring the Depths of React by Cycling Through Arrays in Tabular Format

One issue I'm facing is that I have an array named paymentMethods which I'd like to iterate through in tabs. However, I seem to be struggling with the iteration part. To take a closer look at my code, please visit my codesandbox HERE <div& ...

What is the reason behind Object.hasOwn(x,y) being different from Reflect.ownKeys(x).includes(y) when x represents a CSSStyleDeclaration object and y is a hyphenated property such as 'z-index'?

Both of these conditions are true: 'z-index' in getComputedStyle(document.body) // true Reflect.has(getComputedStyle(document.body), 'z-index') // true Additionally, the following statements also evaluate to true, indicating that &apo ...

Error: Unable to cast value "undefined" to an ObjectId for the "_id" field in the "User" model

Whenever a user logs into their account, I am trying to retrieve their data on the login screen. The login functionality itself works perfectly, but unfortunately, the user data is not displaying. I have tried troubleshooting this issue by making changes i ...

What steps can I take to address the problem in iOS 17 where sound is coming from the earpiece instead of the speaker during camera activation?

I have a Progressive Web App where I use the getUserMedia() API to access the camera and HTML audio tags for handling media content. However, ever since updating to iOS 17, I've faced an issue where audio plays through the earpiece instead of the medi ...

A guide to implementing offline.js or online.js alongside a submit button

I am looking for a way to check network connection only when the user presses the SUBMIT button, without constantly monitoring for internet connectivity. After researching websites and Stack Overflow questions for weeks, I have not found a satisfactory sol ...

Guide to delivering a PDF document from a controller

In my pursuit to send a PDF file from a Controller Endpoint using NestJs, I encountered an interesting issue. Without setting the Content-type header, the data returned by getDocumentFile function is successfully delivered to the user. However, when I do ...

Why am I encountering an issue while trying to access req.user.id?

Having set up passport authentication on my express, node project, I encountered an error when trying to access req.user. The error message displayed is Property 'id' does not exist on type 'User'.ts(2339). Below is the relevant code sn ...