17

I am using HTML5 for uploading files. I have a button click event attached to the function uploadFile(). It works fine. I also have a separate button to cancel the upload. I know we need to call xhr.abort() but how do I access the xhr object in the uploadCanceled function? I can make the xhr object global but that is not the proper way. Can someone guide me here?

function uploadFile(){ 
    var filesToBeUploaded = document.getElementById("fileControl"); 
    var file = filesToBeUploaded.files[0]; 
    var xhr= new XMLHttpRequest(); 
    xhr.upload.addEventListener("progress", uploadProgress, false);
    xhr.addEventListener("load", uploadComplete, false);
    xhr.addEventListener("error", uploadFailed, false);
    xhr.addEventListener("abort", uploadCanceled, false);


    xhr.open("POST", "upload.php", true); 

    var fd = new FormData();
    fd.append("fileToUpload", file);
     xhr.send(fd); 
}


    function uploadCanceled(evt) {
        alert("Upload has been cancelled");
    } 

Cheers

Flynn Hou
  • 429
  • 1
  • 6
  • 18
lewis
  • 181
  • 1
  • 1
  • 5
  • Are you trying to access `xhr` once it's been aborted (within `uploadCanceled`) or do you need to reach it so you can call `abort`? Your question and your comments below don't seem to line up with each other. – Jonathan Lonowski Oct 29 '11 at 17:29

4 Answers4

16

addEventListener will set the context (this) of uploadCanceled to xhr:

function uploadCanceled(evt) {
    console.log("Cancelled: " + this.status);
}

Example: http://jsfiddle.net/wJt8A/


If, instead, you need to trigger xhr.abort through a "Cancel" click, you can return a reference and add any listeners you need after that:

function uploadFile() {
    /* snip */
    xhr.send(fd);

    return xhr;
}

document.getElementById('submit').addEventListener('click', function () {
    var xhr = uploadFile(),
        submit = this,
        cancel = document.getElementById('cancel');

    function detach() {
        // remove listeners after they become irrelevant
        submit.removeEventListener('click', canceling, false);
        cancel.removeEventListener('click', canceling, false);
    }

    function canceling() {
        detach();
        xhr.abort();
    }

    // detach handlers if XHR finishes first
    xhr.addEventListener('load', detach, false);

    // cancel if "Submit" is clicked again before XHR finishes
    submit.addEventListener('click', canceling, false);

    // and, of course, cancel if "Cancel" is clicked
    cancel.addEventListener('click', canceling, false);
}, false);

Example: http://jsfiddle.net/rC63r/1/

Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
  • 2
    @moderns Not entirely. The focus of this answer, `xhr.status` and `xhr.abort()`, are supported in IE7. But, [`addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener) is only supported by IE9 and later. Previous versions instead used [`attachEvent()`](http://msdn.microsoft.com/en-us/library/ie/ms536343.aspx). "[Correct usage of addEventListener() / attachEvent()?](http://stackoverflow.com/questions/2657182/correct-usage-of-addeventlistener-attachevent)" Also, `FormData` from the question requires [IE 10 and later](http://caniuse.com/#feat=xhr2). – Jonathan Lonowski May 20 '14 at 15:12
  • @moderns no need to bother: just use `onclick` and `onload` directly. – Knu Jul 01 '18 at 18:35
2

You should be able to reference the "this" keyword in your canceledUpload event handler. That refers to the XMLHttpRequest. Put this in the handler:

this.abort();
dnuttle
  • 3,810
  • 2
  • 19
  • 19
  • thanks for the reply. But how do I call the uploadCanceled function with the help of a button ? I know it will be called if I reload the page . I dont think I can associate it to a onClick event and then use this.abort() right ? – lewis Oct 29 '11 at 17:07
  • Look at this: http://jsfiddle.net/yE8r3/ The code doesn't run here but shows how to wrap things in a closure. The object named s is visible within the closure, and the click handler, but not outside of the closure. – dnuttle Oct 29 '11 at 17:19
  • what's a `canceledUpload` event handler? – stevemao Sep 16 '15 at 00:57
  • Sorry, should have said "uploadCanceled", which is the name of the function created by the original poster. – dnuttle Oct 20 '15 at 22:56
0

Abort all XMLHttpRequest:

var array_xhr = new Array();
function uploadFile(){ 
    ...
    var xhr = new XMLHttpRequest(); 
    array_xhr.push(xhr);
    ...
}

function abort_all_xhr(){
  if (array_xhr.length>0) {
        for(var i=0; i<array_xhr.length; i++){
            array_xhr[i].abort();
        }
        array_xhr.length = 0;
    };
}

abort_all_xhr();
Jack
  • 131
  • 2
  • 1
    if is unnecessary, for checks that condition anyways. Setting .length did not seem good. You can pop them one by one or assign the array to [] – daghan Jan 15 '16 at 14:36
0

You can use AbortController and fetch to abort requests.

Demo

Code

const btn = document.getElementById('btn');
const btn2 = document.getElementById('btn2');
const url = 'https://www.mocky.io/v2/5185415ba171ea3a00704eed?mocky-delay=1000ms';

const ctrl;

btn.addEventListener('click', e => {
  ctrl = new AbortController();
  const signal = ctrl.signal;

  fetch(url, { signal })
    .then(r => r.json())
    .then(r => {
      console.log('Request result', r);
    }).catch(e => {
      console.error('Request was aborted. Error:', e);
    })
});

btn2.addEventListener('click', e => {
  ctrl.abort();
});
WebBrother
  • 1,447
  • 20
  • 31
  • Note that it's not supported by our good friend, IE. https://developer.mozilla.org/en-US/docs/Web/API/AbortController#Browser_compatibility – ton Sep 10 '19 at 20:55