Cancel event on input type="file"

JavascriptJqueryFile Upload

Javascript Problem Overview


I am working with a standard file input for uploads, and I am looking for a way to attach a function to an event when the user clicks/hits enter on the "cancel" button (or escapes out from) the choose file dialog.

I can't find any events that work across all browsers and platforms consistently.

I've read the answers to this question: https://stackoverflow.com/questions/10127492/capturing-cancel-event-on-input-type-file but they don't work, as the change event doesn't fire in most browsers on canceling out of the choose file dialog.

I'm looking for a pure js solution, but open to jquery solutions as well.

Anyone solve this problem successfully?

Javascript Solutions


Solution 1 - Javascript

A bit of research indicates that there is no way to detect when Cancel is selected in the File Selection dialog window. You can use onchange or onblur to check if files have been selected or if something has been added to the input value.

This could look like: https://jsfiddle.net/Twisty/j18td9cs/

HTML

<form>
  Select File:
  <input type="file" name="test1" id="testFile" />
  <button type="reset" id="pseudoCancel">
    Cancel
  </button>
</form>

JavaScript

var inputElement = document.getElementById("testFile");
var cancelButton = document.getElementById("pseudoCancel");
var numFiles = 0;

inputElement.onclick = function(event) {
  var target = event.target || event.srcElement;
  console.log(target, "clicked.");
  console.log(event);
  if (target.value.length == 0) {
    console.log("Suspect Cancel was hit, no files selected.");
    cancelButton.onclick();
  } else {
    console.log("File selected: ", target.value);
    numFiles = target.files.length;
  }
}

inputElement.onchange = function(event) {
  var target = event.target || event.srcElement;
  console.log(target, "changed.");
  console.log(event);
  if (target.value.length == 0) {
    console.log("Suspect Cancel was hit, no files selected.");
    if (numFiles == target.files.length) {
      cancelButton.onclick();
    }
  } else {
    console.log("File selected: ", target.value);
    numFiles = target.files.length;
  }
}

inputElement.onblur = function(event) {
  var target = event.target || event.srcElement;
  console.log(target, "changed.");
  console.log(event);
  if (target.value.length == 0) {
    console.log("Suspect Cancel was hit, no files selected.");
    if (numFiles == target.files.length) {
      cancelButton.onclick();
    }
  } else {
    console.log("File selected: ", target.value);
    numFiles = target.files.length;
  }
}


cancelButton.onclick = function(event) {
  console.log("Pseudo Cancel button clicked.");
}

I suggest making your own cancel or reset button that resets the form or clears the value from the input.

Solution 2 - Javascript

I have a perfect solution.

The focus event will be executed before the change event.

So I need to use setTimeout to make the focus method execute later than the change method.

const createUpload = () => {
	let lock = false
	return new Promise((resolve, reject) => {
		// create input file
		const el = document.createElement('input')
		el.id = +new Date()
		el.style.display = 'none'
		el.setAttribute('type', 'file')
		document.body.appendChild(el)

		el.addEventListener('change', () => {
			lock = true
			const file = el.files[0]
			
			resolve(file)
			// remove dom
			document.body.removeChild(document.getElementById(el.id))
		}, { once: true })

		// file blur
		window.addEventListener('focus', () => {
			setTimeout(() => {
				if (!lock && document.getElementById(el.id)) {
					reject(new Error('onblur'))
					// remove dom
					document.body.removeChild(document.getElementById(el.id))
				}
			}, 300)
		}, { once: true })

		// open file select box
		el.click()
	})
}



try {
    const file = createUpload()
    console.log(file)
} catch(e) {
    console.log(e.message) // onblur
}

Solution 3 - Javascript

In your "inputElement.onclick" you should set a flag (in my case I set window.inputFileTrueClosed = true) so you can detect when the window gets the focus after pressing the button "Cancel" for that type of event. The following detect if the window gets the focus again: it means that "Cancel" button could have been pressed:

var isChrome = !!window.chrome;

    window.addEventListener('focus', function (e) {
       
    
    if(window.inputFileTrueClosed != false){
      
        if(isChrome == true){
           setTimeout(
                    function() 
                    {
                         if(window.inputFileTrueClosed != false){
   //if it is Chrome we have to wait because file.change(function(){... comes after "the window gets the focus"
                         window.inputFileTrueClosed = false; 
                         }
                    }, 1000);
}
else
{
        // if it is NOT Chrome (ex.Safari) do something when the "cancel" button is pressed.

        window.inputFileTrueClosed = false;
        
    }
}
})

Obviously the window gets the focus for many other events BUT with the flag you can select the one you need to detect.

Solution 4 - Javascript

When we select the file following events are called -

Scenario 1 : When the select file is clicked and then cancel is clicked

Focus event value=""

Click event value=""

Blur event value=""

Focus event value=""

Blur event value="" (when the user clicks somewhere out)

Scenario 2 : When the file is selected -

Focus event value=""

Click event value=""

Blur event value=""

Focus event value=""

Change event value="filevalue"

Blur event value="filevalue"

Focus event value="filevalue"

Blur event value="filevalue" (when the user clicks somewhere out)

We see here, when the Blur event (last event) is called after focus event with no value of file means that the Cancel button is clicked.

My scenario was to change the Submit button text to "Please wait" while the file is loading currentEvent variable is used to hold the current event value either click or focus if the currentEvent = focus and file value is null means Cancel button is clicked.

Javascript

var currentEvent = "focus";

function onFileBrowse() {    
    var vtbFile = $('#uploadFile')[0].files[0];

    if (vtbFile != undefined) {
        var extension = vtbFile.name.split('.').pop().toLowerCase();
        var valError = "";

        if (extension === 'xlsx' || extension === 'xlsb' || extension === 'csv') {
            if (vtbFile.size === 0)
                valError = "File '" + vtbFile.name + "' is empty";
        }
        else
            valError = "Extension '" + extension + "' is not supported.";

        if (valError !== "") {            
            alert("There was an issue validating the file. " + valError, 20000);
        }        
    }
    //hide Indicator
    var buttonUpload = document.getElementById('btnUploadTB');
    buttonUpload.innerText = "Submit";
};


function fileClick() {
    //show Indicator
    var buttonUpload = document.getElementById('btnUploadTB');
    buttonUpload.innerText = "Please wait..";
    
    document.getElementById('uploadFile').value = null;   
    currentEvent = "click";
}
function fileFocus() {
    currentEvent = "focus";
}

function fileBlur() {
    
    if (!document.getElementById('uploadFile').value && currentEvent == "focus") {
        console.log('blur' + 'change to submit');
        //hide Indicator
        var buttonUpload = document.getElementById('btnUploadTB');
        buttonUpload.innerText = "Submit";
    }
}

HTML

<input class="k-button k-upload-button" type="file" id="uploadFile" name="uploadFile"
    accept=".csv,.xlsx,.xlsb" onChange='onFileBrowse()' onclick="fileClick()" onfocus="fileFocus()" onblur="fileBlur()" />

<button id="btnUploadTB" type="button" class="btn btn-default" onclick="uploadTBFile()" style="width:28%;margin-left: 3px;">Submit</button>

Solution 5 - Javascript

I had the problem where I clicked the cancel button on the input type="file" element and wanted the function to do nothing. if something was selected and I clicked the open button then I wanted my function to do something. The example only shows the method, I stripped out what I do with it after it opens. I put in the alerts just so you could see there isn't a filename coming back from the dialog when cancel is clicked. Here is a method I use, it is simple but it works.

 function openFileOnClick(){
    document.getElementById("fileSelector").value = "";
    document.getElementById("fileSelector").files.length = 0;            
    document.getElementById("fileSelector").click();
    if(document.getElementById("fileSelector").files.length >= 1){
        alert(document.getElementById("fileSelector").value);
        //Do something 
    }
    else{
        alert(document.getElementById("fileSelector").value);
        //Cancel button has been called.
    }
}

<html>
<head>
</head>
<body>
<input type="file" id="fileSelector" name="fileSelector" value="" style="display:none;"  />
<input type="button" value="Open File" name="openFile" onclick="openFileOnClick();" />
</body>
</html>

Solution 6 - Javascript

I was wrestling with a similar issue after implementing an automatic submit of an image upload form using jQuery. If the user cancelled the dialogue it sent a blank. All that was needed was to detect this empty value in the same script:

$('#upload-portrait-input').on('change', function(){
   if ( $(this).val() != '' )
    {
    $('#portraitForm').submit();
    }
   else { // do something when the user clicks cancel
    }
 });

Solution 7 - Javascript

I needed to style my file upload differently whether the user was browsing the file explorer (active/inactive). Only click and blur events. Just consider that when the user clicks the Cancel button, a click outside the file upload (button in my case) is required.

Here is my solution for Angular, but I guess anyone can grab the idea and adapt it with your favorite framework/library/Vanilla JS.

<!-- HTML - Angular -->

<input hidden type="file" #fileInput (change)="onFileUpload($event.target.files)">
<button (click)="initBrowsingFlags(); fileInput.click()" (blur)="onBlur()" [class.browsing]="browsing">Upload</button>
// Typescript - Angular

/** Whether the user is browsing the file explorer. */
browsing = false;

/** 
 * If a 2nd `blur` event is emitted while {@link browsing} is still true, it means that the user
 * clicked the Cancel button on the file explorer.
 * */
alreadyOneBlurEventWhileBrowsing = false;

onFileUpload(files: FileList) {
  // ...
  this.resetBrowsingFlags();
}

onBlur() {
  if (!this.browsing) return;

  if (this.onCancelClickWhileBrowsing) {
    this.resetBrowsingFlags();
  } else {
    this.onCancelClickWhileBrowsing = true;
  }
}

initBrowsingFlags() {
  this.browsing = true;
  this.alreadyOneBlurEventWhileBrowsing= false;
}

resetBrowsingFlags() {
  this.browsing = false;
  this.alreadyOneBlurEventWhileBrowsing= false;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGWRView Question on Stackoverflow
Solution 1 - JavascriptTwistyView Answer on Stackoverflow
Solution 2 - JavascripthoythanView Answer on Stackoverflow
Solution 3 - JavascriptgiuseppeView Answer on Stackoverflow
Solution 4 - JavascriptAnshika SrivastavaView Answer on Stackoverflow
Solution 5 - JavascriptDJonesView Answer on Stackoverflow
Solution 6 - JavascriptOroonokoView Answer on Stackoverflow
Solution 7 - JavascriptBruno MartinsView Answer on Stackoverflow