My attempts to transfer the blob payload via FormData were unsuccessful

I've been experimenting with the FormData API. You can check out the fiddle I'm working on here - my goal is to embed blobs into my form and submit it via AJAX.

//ic0 and tc0 represent canvases
//image0 and thumb0 are file inputs
function ajaxSubmit(){
    var fd = new FormData(document.forms[0]);
    ic0.toBlob(
        function(blob){
            fd.set("image0", blob, "image0.jpg");
        }, "image/jpeg", 0.7);
    tc0.toBlob(
        function(blob){
            fd.set("thumb0", blob, "thumb0.jpg");
        }, "image/jpeg", 0.7);
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/ajax-upload/", true);
    xhr.send(fd);
}

The behavior of browsers seems a bit peculiar:

Chrome 50 (in Ubuntu)

Encounters an issue, displaying:

Failed blob:https%3A//fiddle.jshell.net/uuid4 to load resource: the server responded with 404

I thought FormData.set() was now supported? It works with non-blobs, right?

Firefox 46 (in Ubuntu)

If the FormData() object is not initialized with an existing DOM object containing necessary file inputs, it doesn't seem to work as expected. FormData.set() doesn't appear to function properly with file inputs and blobs (despite calling

fd.set("thumb0", blob, "thumb0.jpg")
, resulting in thumb0 being null in the payload. By checking
console.log(fd.get("thumb0"))
immediately after setting, you'll notice that the value is indeed set. Additionally, the payload for image0 turns out to be the original image instead of the resized canvas image.


It's inconvenient not being able to customize multipart FormData using JavaScript. As someone relatively new to JavaScript, am I missing something crucial here, or could these browsers potentially have issues supporting the FormData API correctly? How do I correctly submit image0 and thumb0 in my fiddle?


Edit: Deciding to prioritize this. I'm aware of larger jQuery-dependent libraries like blueimp, but I prefer transmitting data as file inputs rather than basing it in base64 (and avoiding jQuery altogether). For this project, I only need support for the latest versions of Chrome and Firefox and hope to maintain clean code as suggested by the FormData API. Can anyone successfully extract an image from a canvas and include it in the POST payload as a file? Ideally, I'd like to access it in request.FILES within Django.

Answer №1

One element that seems to be overlooked is the asynchronous nature of JavaScript within your ajaxSubmit method -

function ajaxSubmit(){
    var fd = new FormData(document.forms[0]);
    ic0.toBlob(function(blob){
        fd.set("image0", blob, "image0.jpg");
    }, "image/jpeg", 0.7);                // this call operates asynchronously
    tc0.toBlob(function(blob){
        fd.set("thumb0", blob, "thumb0.jpg");
    }, "image/jpeg", 0.7);                // similarly, this call is also asynchronous
    /*
       Consequently, the code below may execute before
          fd.set("image0", blob, "image0.jpg");
       this statement. As a result, the canvas files are not submitted.
    */
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/ajax-upload/", true);
    xhr.send(fd);
}

To sync the code, you can adjust it as follows:

function ajaxSubmit(){
   var fd = new FormData(document.forms[0]);
   ic0.toBlob(function(blob){
      fd.set("image0", blob, "image0.jpg");
      tc0.toBlob(function(blob){
         fd.set("thumb0", blob, "thumb0.jpg");
         console.log(blob);
         console.log("Just processed thumb0");

         var xhr = new XMLHttpRequest();
         xhr.open("POST", "fileuploadbackend.jsp", true);
         xhr.send(fd);
      }, "image/jpeg", 0.7);

   }, "image/jpeg", 0.7);
}

Also, as advised by jornare, consider commenting out the line

URL.revokeObjectURL(img.src);

This line is causing an error in Chrome. Call it after the image has finished loading.

You have multiple elements with the same id,

<input id="image0" name="image0" type="file" />
<label for="image0">image0</label> 
<input id="image0" name="thumb0" type="file" />

Although this isn't causing issues in your code, different ids should be used.

UPDATE

Here's the functioning fiddle.

Please remember to update the request URL according to your requirements.

Explore the following links to delve deeper into the asynchronous behavior of JavaScript and how AJAX request callbacks are managed.

Answer №2

Upon reviewing your code on Fiddle, it appears that the dataURL was being cleaned up before it could be loaded, resulting in the thumbnails not appearing (hence the 404 error).

To address this issue, I have created an updated version of your Fiddle: https://jsfiddle.net/tLqch5x2/3/

function handleFiles(e){
    var img = new Image();
    img.onload = function(){
        var width = 30;
        var height = img.height * 30/img.width;
        e.target.ic0.width = width ;
        e.target.ic0.height = height ;
        e.target.tc0.width = width/2 ;
        e.target.tc0.height = height/2;
        var ctx = e.target.ic0.getContext("2d");
        ctx.drawImage(img, 0, 0, width, height);
        ctx = e.target.tc0.getContext("2d");
        ctx.drawImage(img, 0, 0, width/2, height/2);
        URL.revokeObjectURL(img.src); //cleanup memory here instead
    };
    img.src = URL.createObjectURL(e.target.files[0]);
    //perform cleanup to prevent memory leak
    //URL.revokeObjectURL(img.src); //too early
}

In testing the updated Fiddle, there still seems to be a 404 error due to attempting to post to a non-existent URL on jsfiddle.net. I recommend running the code in your own environment for further testing.

Additionally, I made some minor modifications to both the HTML and code sections such as correcting image naming conventions and eliminating unnecessary references to existing forms when creating new ones for submission.

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

When using AngularJS ng-repeat to populate a table, three empty rows are mistakenly created instead of repeating the content

Attempting to overcome these challenges, I have delved into the world of Angular, but the syntax remains elusive and the methods seem to perform complex operations behind the scenes. As a newcomer to web development embarking on my first project involving ...

What techniques did Google Maps use to incorporate multiple click-event handlers within a single image?

After discovering that the control panel in Google Maps is actually one whole image, I realized that clicking on different parts of it can result in different actions. Now I'm curious about how to incorporate this feature into my own project. ...

Top choice for removing items from a list array

Hey there, I'm working with an array of a custom type in Angular: List { task: string; id?: number; status?: boolean; } I'm trying to figure out how to delete elements where List.status == true. I've tried two methods for this. ...

Sending a group of checkboxes via Ajax using AngularJS

I am facing a challenge with making an ajax GET request where I need to submit an array of checkboxes, all with the same name. The checkboxes are defined as follows: type[] = new type[] = used type[] = refurbished The purpose of this is to fulfill the r ...

Using ReactJS to integrate a pananorama application with Three.js

Looking to experiment with this application on JsFiddle. I want to find a way to enhance the demo and prevent the tearing issue that is currently present. //The latest JsFiddle link but it shows broken 404 errors for the images. https://jsfiddle.net/7xzd9 ...

Conceal element with Wicket while AjaxButton is loading lazily

I am having an issue with an AjaxLazyLoadPanel on my page, which contains a long-loading list and a submitting AjaxButton. Once the AjaxLazyLoadPanel is fully loaded, upon submission, another long-loading process begins, requiring me to refresh the entire ...

My date function in Node JS is throwing an error, can someone please help me troubleshoot?

I encountered an error with new date(); while working with node js and express npm plugin. I built a variable date but faced some compilation errors. This is my code .js var update_time = new Date(); update_time.formatDate("y/m/d"); When I run ...

Component does not detect change when the same number is sent as input

Let me paint you a picture: I have this nifty component, set up with the OnPush strategy, that showcases a PDF document, sliding through pages one by one, and granting users the ability to smoothly glide through pages and jump to specific ones. It even of ...

When using JS, the open and close buttons function properly, however, the escape key always attempts to close the most recent modal

My buttons are working fine, but I'm having trouble getting the escape key to work with the correct modal. It keeps closing the last modal no matter how many I have. Even though thisModal seems to point to the right one for the buttons, it doesn&apos ...

What kind of content can be duplicated but remains untraceable through search engines?

In the past, I utilized the alt attribute of images to generate text that could be copied to the clipboard: The style attribute can conceal text, however, hidden text still remains and can be discovered using methods like indexOf or control-F. Is there a ...

Is it possible to open a new tab by clicking on an anchor tag

I have a scenario with two tabs on a webpage, each with anchor tags that I can navigate to from the homepage using a header menu item anchor. The tabs are working fine with an active class and aria-expanded="true", but I'm facing an issue where the ap ...

Performing complete postbacks using ASP.Net AJAX on an ASP.NET webpage embedded within an IFRAME

I am facing an issue with my ASP.Net page that is enclosed within an iframe. The page contains an update panel which works fine when isolated, but within the iframe, it always causes a full postback. I suspect the problem lies with the iframe itself and I ...

Invoking Swift from a UIWebView using Javascript

Hey there! I am currently exploring the process of making a call from a JavaScript function in a UIWebView to Swift in iOS 10. To do this, I have set up a basic project for testing purposes, and you can find the code below. import UIKit class ViewControl ...

Employ node's gm library in combination with promises and buffers

Using gm with Bluebird has been a bit tricky for me. Initially, I tried this approach: var gm = require('gm'); var bluebird = require('bluebird'); gm = bluebird.promisifyAll(gm); However, when attempting to execute the following code: ...

Creating your own XSRF protection system using Laravel and React

I am currently utilizing Next.js on the frontend in combination with Laravel as an API to develop a Shopify application. For authentication (OAuth), I have opted to utilize Shopify's PHP API library instead of Laravel's built-in auth. My focus no ...

Exchanging items through Drag and Drop

My current project involves using drag and drop functionality to allow students to rearrange pieces of an image that has been jumbled up. They can drag these pieces onto a grid to recreate the original image. Both the jumbled up grid and the reconstructio ...

Securing access for a Single Page Application and a Node.js server

I have a node.js application built on express that currently uses a session memory store for authentication. The user logs in by sending a POST request to '/sessions' and if the credentials are valid, the user is authenticated. app.post('/s ...

Tips for adjusting the status bar color in iOS for a React Native drawer

Is there a way to change the default color above the drawer navigator from white to red on iOS? I want all navigated screens to always display the color we set. https://i.sstatic.net/QszUDgmn.png import React from 'react'; import { View, Text, S ...

Issues arise with the functionality of Zurb Foundation 5 tabs

Utilizing the tabs feature in ZURB Foundation 5, I've noticed that clicking on a tab changes the hash in the URL. However, I actually want to prevent this behavior as I rely on the hash for managing page loads. Although I attempted to use preventDef ...

"Using PHP functionality based on the output of a JavaScript function

I'm currently working on a php/html page that involves implementing some javascript functions. My goal is to execute an INSERT query in my MySQL Database only if the result of one of my javascript functions returns 1. 01) Is there a way for me to re ...