The issue of data loss in a PDF file while using the FileReader

My current challenge involves the necessity of sending data to a server in JSON format exclusively, and I also need to include a PDF file along with other form data within the JSON. Initially, I attempted to convert the PDF into a base64 string following a similar approach outlined in this solution that I stumbled upon on SO:

let data = {foo: 1, bar: 2};
let reader = new FileReader();
reader.readAsDataURL(pdf);
reader.onload = () => {
  data.file = reader.result;
  $.ajax({type: 'POST', dataType: "json", data: JSON.stringify(data), ...});
}

To my dismay, it turned out that reader.result does not encompass the entire PDF content (whether saved to file or retrieved from the server). While the text editor displays consistent content, a binary analysis reveals missing bytes. Although my browser manages to load it as a PDF and display the title, the page remains blank.

Despite experimenting with reader.readAsBinaryString and converting it to base64 using btoa, the outcome remained unaltered.

Edit: Link to CodePen example: https://codepen.io/jdelafon/pen/eRWLdz?editors=1011

Edit: To validate this, I performed the following:

let reader = new FileReader();
reader.readAsBinaryString(pdf);
reader.onload = () => {
    let blob = reader.result;
    let file = new Blob([blob], {type: 'application/pdf'});
    let fileURL = window.URL.createObjectURL(file);
    // render it within <embed>
};

The PDF's body appears empty. Substituting file with the original pdf enables complete display. Hence, FileReader seems to lose data in the process.

https://i.sstatic.net/0RL8d.png

Is there an improved method available? Could it be linked to an encoding complication with FileReader?

I contemplated utilizing FormData like so:

let data = {foo: 1, bar: 2};
let fd = new FormData();
fd.append('file', pdf);
data.file = btoa(fd);
$.ajax({type: 'POST', dataType: "json", data: JSON.stringify(data), ...});

However, retrieving the data from the server poses a challenge since JavaScript fails to recognize it as a FormData object. Consequently, I am uncertain how to retrieve the file for browser rendering. Is there a feasible solution?

Answer №1

Almost there with the attempt to use btoa, but unfortunately FormData can't be "btoa-ized".

reader.readAsBinaryString(pdf); // avoid using this method, refer to the edit below
reader.onload = () => {
  let b64payload = btoa(reader.result);
  $.ajax({
    type: 'POST',
    dataType: "json",
    data: JSON.stringify({ "file": b64payload }),
  });
}

The reason for the failure of the readAsDataURL solution is unclear.


Note: There are suspicions that the issue might be related to the deprecated readAsBinaryString method. The following alternative solution using readAsDataURL has proven to work:

reader.readAsDataURL(pdf);
reader.onload = () => {
  $.ajax({
    type: 'POST',
    dataType: "json",
    data: JSON.stringify({ "dataURL": reader.result }),
  });
};

Answer №2

Unfortunately, Watilin's response was not included. Here is the functional snippet obtained from Codepen:

function onUpload(input) {  
  let originalFile = input.files[0];
  let reader = new FileReader();
  reader.readAsDataURL(originalFile);
  reader.onload = () => {
    let json = JSON.stringify({ dataURL: reader.result });

    // Display the file
    let fileURL = JSON.parse(json).dataURL;
    $("#display-pdf").empty();
    $("#display-pdf").append(`<object data="${fileURL}"
      type="application/pdf" width="400px" height="200px">
    </object>`);

    // Show the original file
    let originalFileURL = URL.createObjectURL(originalFile);
    $("#display-pdf").append(`<object data=""${originalFileURL}"
      type="application/pdf" width="400px" height="200px">
    </object>`)
    .onload(() => {
      URL.revokeObjectURL(originalFileURL);
    });
  };
}

HTML:

<input id="file-input" type="file" onchange="onUpload(this)" />
<div id="display-pdf"></div>

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

How can I use a ping in Javascript to evaluate an IF statement?

Welcome to my first post on this forum! I am working on a project for a mobile browser (specifically Android). I am trying to determine if a computer is turned on before deciding which function to execute. Is there a way to ping the computer to check its ...

Sending an Array of Data to Jquery

One of the buttons in my code looks like this: <button id='abc' value=['fred', 26]></button> I am looking for a way to retrieve the two values using JQuery's .val() function. My attempt $("#abc").val()[0] only return ...

Creating a service function (constructor) in JavaScript

When working with AngularJs and calling a service method: app.service('nameService', function() { this.Service = function (){console.log('hello')} } You can then use this service (object) like so: nameService.Service() My question is, ...

The error message "Failed to load the default credentials in Firebase" occurs sporadically. Approximately 50% of the time, the app functions properly, while the other 50% of the time, this specific

Occasionally in my firebase functions log, I encounter an error message stating: "Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information." This error appears randomly withi ...

Tips for utilizing console log within a react form component

I'm currently exploring ways to communicate with a React form in order to provide it with an object.id for updating purposes. While I can successfully console log the object.id within the update button and modal, I am struggling to confirm if the val ...

Ways to prevent my website from being accessed through the Uc Browser

Is there a way to prevent my website from functioning on UC Browser using HTML or JavaScript? ...

How to insert a new document into a MongoDB collection with Mongoose

Consider a scenario where my existing collection called fruits is structured as follows: {"_id" : ObjectId("xyz...."), "name" : "Apple", "rating" : 7} {"_id" : ObjectId("abc...."), " ...

Combining React with Typescript allows for deep merging of nested defaultProps

As I work on a React and Typescript component, I find myself needing to set default props that include nested data objects. Below is a simplified version of the component in question: type Props = { someProp: string, user: { blocked: boole ...

Converting array elements to strings when extracting in JSON with JavaScript

I am working with a Json document that looks like this: { "_id": "13fee4aad95c7f822c0b559bd8d09fb0", "_rev": "5-336dea3680af3e7ec0de29369be90b09", "attributeCollection": { "attributeArray": [ { "name": "Web Issue", "val ...

Is there a way to dynamically insert page breaks in jspdf to ensure that tables do not split across multiple pages?

I am currently working on developing a website that can generate PDFs from database information, using PHP and MySQL to create tables with variable lengths. Sometimes, these tables may even span across multiple pages. If the first table takes up too much ...

Retrieving information from Mongodb using Angularjs

Although my background is in a LAMP stack, my interest has recently been piqued by the Node.js/Angluarjs combo. I now want to incorporate Mongodb into the mix, but I'm struggling to set it up. Every tutorial I come across seems to use a different stac ...

The expect.objectContaining() function in Jest does not work properly when used in expect.toHaveBeenCalled()

Currently, I am working on writing a test to validate code that interacts with AWS DynamoDB using aws-sdk. Despite following a similar scenario outlined in the official documentation (https://jestjs.io/docs/en/expect#expectobjectcontainingobject), my asser ...

changing the visible style of a div element using JavaScript

I'm having an issue with a link on my webpage that is supposed to show or hide a <div id="po" style="display:none;">some html</div> element. The first time I click the link, the div displays properly. However, after tha ...

Tips for accessing elements using document.getElementsByTagName

Greetings and best wishes for the holiday season! I hope everyone is cozy and safe. I need a little help with some code here, as I am fairly new to JavaScript but not entirely new to programming. Despite finding an answer on this site, I am still encounter ...

What is the best way to access the CSS font-size property using JavaScript?

I've attempted to adjust the font size using this code: document.getElementById("foo").style.fontSize Unfortunately, this code does not return any results. The CSS styles are all defined within the same document and are not in an external stylesheet ...

Strategies for efficiently updating specific objects within a state array by utilizing keys retrieved from the DOM

I am trying to figure out how to use the spread operator to update state arrays with objects that have specific ids. Currently, I have an array called "todos" containing objects like this: todos: [ { id: "1", description: "Run", co ...

Update Table Row Background Color in Separate Table by Clicking Button Using JQuery

Two tables are involved in this scenario - one that receives dynamically added rows, and another that stores the data to be included. The illustration above displays these tables. Upon clicking the Edit button, the information from the selected row in Tab ...

Exploring the concept of generator functions in ES6

I'm grappling with understanding JS generators and why the asynchronous operations in the example below are returning undefined. I thought that using yield was supposed to wait for asynchronous calls to finish. function getUsers(){ var users; $.aj ...

Implementing a jQuery change event to filter a specific table is resulting in filtering every table displayed on the page

I have implemented a change event to filter a table on my webpage, but I am noticing that it is affecting every table on the page instead of just the intended one. Below is the code snippet: <script> $('#inputFilter').change(function() { ...

Incorporating a JavaScript script into my Angular 7 project

My project requires me to incorporate the "Loadingbar.js" library into one of my pages. You can find this library here: . Initially, I inserted the CSS code into my global "style.css" file. I started by placing the script in my index.html file: <script ...