Transmit the canvas image and anticipate the AJAX POST response

I need to send canvas content to my API endpoint using ajax and wait for the response before moving on to the next function. Here is my current sending function:

function sendPicture(){
  var video = document.getElementById('video');
  var canvas = document.getElementById('canvas');

  var context = canvas.getContext('2d');
  if (width && height) {
    canvas.width = width;
    canvas.height = height;
    context.drawImage(video, 0, 0, width, height);

    var fd = new FormData();
    fd.append('video', null);

    var reso;
    canvas.toBlob(function(blob){
        fd.set('video', blob);
    }, 'image/jpeg');

    reso = $.ajax({
      url: "/img",
      type : "POST",
      processData: false,
      contentType: false,
      data : fd,
      dataType: "text",
    });

    return reso;
  }
}

The ajax statement works within the toBlob callback, but I lose access to the main scope. I'd like to find a way to block the ajax promise outside of the callback. Perhaps extracting the blob argument from the callback scope or ensuring that fd.set('video', blob) sets the formData object outside where it was initially created would help.

Any suggestions on how to convert the canvas to a blob without using the callback method? Or any ideas on how to fill the formData in the outer scope?

Answer №1

There is a method to obtain the width and height, though it may be confusing at first glance. The key is to create a function outside of the callback and then invoke it within the callback. This allows you to access the data from both inside and outside of the callback.

function sendPicture(){
     var video = document.getElementById('video');
     var canvas = document.getElementById('canvas');

     var context = canvas.getContext('2d');
     if (width && height) {
       canvas.width = width;
       canvas.height = height;
       context.drawImage(video, 0, 0, width, height);
     }

     var fd = new FormData();
     fd.append('video', null);

     var setBlobOutside = function(blob){
       fd.set('video', blob);
     }
     
     var reso;
     canvas.toBlob(function(blob){
         setBlobOutside(blob);
     }, 'image/jpeg');

     reso = $.ajax({
       url: "/img",
       type: "POST",
       processData: false,
       contentType: false,
       data: fd,
       dataType: "text",
     });

     return reso;
}

Your var fd = new FormData(); is empty because it is not receiving any data or having anything appended to it. You can rectify this by using fd.append('key1', 'value1'); or new FormData([data]);

Below is an example demonstrating how to asynchronously send form data with a file:

<form id="formElem">
  <input type="text" name="firstName" value="John">
  Picture: <input type="file" name="picture" accept="image/*">
  <input type="submit">
</form>

<script>
  formElem.onsubmit = async (e) => {
    e.preventDefault();

    let response = await fetch('/article/formdata/post/user-avatar', {
      method: 'POST',
      body: new FormData(formElem)
    });

    let result = await response.json();

    alert(result.message);
  };
</script>

Answer №2

After finding inspiration in a discussion on how to access blob value outside of the canvas.ToBlob() async function, I opted to utilize a promise constructor for my project. Here is the code snippet showcasing the solution:

function uploadImage(width, height){
  var video = document.getElementById('video');
  var canvas = document.getElementById('canvas');

  var context = canvas.getContext('2d');
  canvas.width = width;
  canvas.height = height;
  context.drawImage(video, 0, 0, width, height);

  return new Promise(function(resolve, reject) {
    canvas.toBlob(function(blob) {
      var formData = new FormData();
      formData.set('image', blob);

      $.ajax({
        url: "/img/upload",
        type : "POST",
        processData: false,
        contentType: false,
        data : formData,
        dataType: "text",
      })
      .done(function(response) {
        resolve(response)
      })
      .fail(function(error) {
        console.log(error);
      });
    })
  })
}

This function can be called within an HTML script like so:

  <script>
    $(function() {
      var captureButton = document.getElementById("captureBtn");
      captureButton.addEventListener('click', function(event){
        var imageUploadPromise = uploadImage(300, 200);

        imageUploadPromise
        .then(function(response){
          console.log(response);
          displayUploadedPhoto();
        });
        event.preventDefault();
      }, false);
    })()
  </script>

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

Array filtering functions similarly to marketplace filtering tools

In order to make the filter function like a marketplace filter, I want to only see items related to the selected brand and status. For example: partners = [ 0:{ year: "2022" badge_status: "badge-success" sale_date: "01/07/2022&quo ...

I encountered an ERR_CONNECTION_REFUSED issue after deploying my Node.js application with Socket.io to Heroku

Upon running my live node.js Heroku app, I encountered the following error message in the web console: polling-xhr.js:264 GET http://localhost:3000/socket.io/?EIO=3&transport=polling&t=M2MDZUw net::ERR_CONNECTION_REFUSED Interestingly, when testin ...

What is the best way to stop the browser from automatically redirecting to another page after submitting a form?

I am using an AJAX call to a method that returns JSON data. How can I retrieve and read the JSON response without being redirected to a new empty page? [HttpPost] public JsonResult Test() { return Json("JSON return test", JsonRequestBehavior.AllowGe ...

After removing an element from an array in Vue.js, how can we adjust its class to reflect the change?

Apologies for my lack of proficiency in English. I am eager to find a solution to resolve these issues. I am working on a todolist and encountering an issue where the class ('centerLine') continues to affect the next element after deleting an a ...

Implementing dynamic loading with a Vue component loader

Is it possible to dynamically import a component using a default Loader if it's not loaded? Currently, we are using the following approach: import Dashboard from '../components/dashboard'; Vue.component('dashboard', Dashboard); ...

I'm having trouble getting onClick to function properly in CodeIgniter

While attempting to utilize onClick in the PHP page as shown below: <a href="javascript:void(0);" onClick="deleteCourse('<?php echo $row->courseId;?>');" class="delete">Delete</a> And in the JavaScript page, the function is ...

Verify if any choices are available before displaying the div block

I need to determine if there is a specific option selected in a dropdown menu, and then display a div if the option exists, otherwise hide it. I'm not just checking the currently selected option, but all available options. if (jQuery(".sd select opti ...

Unable to direct to the main page in index.js of the next.js application

I have been working on a next.js application and encountered an issue with a component I created called <ButtonGroup>. I added a button with the code <Button href="index">Home</Button> to allow users to navigate back to the home ...

Stencil - React Integration Does Not Support Global CSS Styling

As per the guidance provided in the Stencil docshere, I have established some global CSS variables within src/global/variables.css. This file is currently the sole CSS resource in this particular directory. Upon attempting to incorporate my components int ...

Generate tables and rows dynamically

I am looking for guidance on dynamically creating a table and adding rows to it. I have successfully created a table with one row containing form fields, but I am unsure how to add additional rows. Any examples or suggestions on how this can be implemented ...

I'm having trouble with my react-big-calendar not updating when I switch between day, month, or week views -

Why won't my calendar change to the week view when I click on that section? https://i.stack.imgur.com/gh2aO.png In the screenshot above, my default view is set to month, but when I attempt to switch to week, it only highlights the option without cha ...

What is the best way to define properties for objects within views.py so that the updated object can be effectively passed to JavaScript code?

When loading an "endless scroll" feed via AJAX and pagination, I realized that before passing objects to the JS code, I need to add a property (or attribute) to every object indicating whether it was liked by the current user or not. However, my initial ...

Tips for triggering window load event on a particular page

I need to trigger the windows.load event on a specific page. Currently, I have set it up like this: $(window).load(function(){ if(document.URL == "/car-driving.html") { overlay.show(); overlay.appendTo(document.body); $('.popup' ...

Choose a specific parameter from a line using the body parser in Node.js

Upon receiving a post message, I am having trouble selecting a value from CSV data. Here is a sample of what I receive: { reader_name: '"xx-xx-xx-xx-xx-xx"', mac_address: '"name"', line_ending: '\n', field_delim: & ...

Using jQuery to trigger alert only once variable has been updated

I have a question that may seem too basic, but I can't find the solution. How do I make sure that the variables are updated before triggering the alert? I've heard about using callbacks, but in this case, there are two functions and I'm not ...

Increase or decrease the quantity of items by cloning with Jquery and dynamically changing the ID

Currently, I am working on a jQuery clone project where I need to dynamically add and delete rows. Despite searching extensively on Stack Overflow and Google, I only have a basic understanding of how jQuery clone works. Any suggestions would be greatly ap ...

Are you experiencing issues with the map displaying inaccurate latitude and longitude when clicking on a specific point?

I've successfully created a simple polyline on Google Maps and attached a click event listener to it. However, I'm encountering an issue where clicking on the line provides me with latitude and longitude coordinates that point to Canada, even th ...

Triggering a JavaScript function when a page is focused due to user interaction

In my project, I have a specific requirement that involves triggering a new window to open when the user clicks on an icon. In this new window, the user should be able to view and edit certain fields. Upon closing the new window and returning to the parent ...

Displaying JSON data based on a specific key

My current challenge involves dealing with a JSON string structured like this: {"cat1":"m1","cat2":["d1","d2","d3"],"cat3":["m1","m2","m3","m4"]} As part of my learning process in Javascript and AJAX, I am attempting to display the different values based ...

Struggling to display a navigation menu on angular 1 with complex nested json structure

I have set up a navigation bar using JSON data fetched by an Angular service. Everything is working fine with my service and controller, but I am facing difficulty in displaying the nested JSON data in my view. Here is the JSON data: { "menu": [ ...