-1

I am fairly new to the use of javascript and would appreciate any help. I have an application where the browser must use xmlhttprequest to receive a response from the server (true/false for testing purposes) and based on the response, the client will open a file selection dialog for the user to select a local file for uploading.

When I create the XMLHttpRequest with the async flag set to FALSE, when the client receives a "true" response from the server, a file selection dialog box opens (for both Chrome, IE).

When I create the XMLHttpRequest with the async flag set to TRUE ( as recommended), when the client receives a "true" response from the server, the same code path is followed, however a file selection dialog box never opens and no errors are displayed in the debuggers for Chrome, HOWEVER it still work in IE.

Here is the code:

... 
// user has clicked button to upload a file
$scope.uploadFile = function () { 
   request = new XMLHttpRequest();
   request.open("GET", "some-url", true);// false
   request.onreadystatechange = $scope.checkUploadPermissions;
   request.send();    
}

// the callback
// If the user has permission (based on various factors not shown here)
//   we open the dialog
// Otherwise we inform them that they are not allowed
$scope.checkUploadPermissions = function () {
  // simplified for brevity
  if (request.readyState == 4 && request.status == 200) {
    // for this sample, we are only checking if the server returned true/false
    var hasPerms = request.responseText;
    if (hasPerms === "true") {
       $scope.openFileSelector();
    }
    else {
       alert("You do not have permission to upload a file.");
    }
  }
}

// if the user has permission to proceed, we trigger a click on a hidden element
$scope.openFileSelector = function () {       
   angular.element("#presentUpload").trigger("click");
}
...

I would like to reiterate that this code works perfectly when the async flag set to FALSE but not when it is set to TRUE.

How can I have this work properly when setting the flag to TRUE.

Thank you in advance.

codephreek
  • 88
  • 4
  • Usually, when something works sync, but not async, it's because some code in the execution path is wrongly assuming synchronous execution and some things that should be executed in the completion callback are not being done there. – jfriend00 May 09 '16 at 21:32
  • What is the `angular.element("#presentUpload").trigger("click");` supposed to do? Do you know if `openFileSelector()` gets called when you're doing your ajax asynchronously? Some actions in the browser are not allowed to execute asynchronously and will only work if in the middle of processing an actual user event. – jfriend00 May 09 '16 at 21:34
  • @jfriend00 The call to openFileSelector() is just a function that contains any necessary TODOs if the user has permission to upload a file. the call to `angular.element("#presentUpload").trigger("click");` simply calls a hidden button on the html page that opens and triggers a click on `` – codephreek May 09 '16 at 21:44
  • Sorry @jfriend00 got called away from my desk and didn't finish a proper edit to the previous comment: The call to openFileSelector() is just a function that contains any necessary TODOs if the user has permission to upload a file. the call to `angular.element("#presentUpload").trigger("click");` simply calls a hidden element on the html page that triggers a click on `` and opens the file upload dialog. In both cases (async set to TRUE and FALSE) all lines of code are hit, it is just that when it is TRUE, the dialog never opens. – codephreek May 09 '16 at 21:53
  • *"simply calls a hidden element on the html page that triggers a click on – Kevin B May 09 '16 at 22:15
  • @KevinB Yes it does work up until the trigger in both cases (async flag set to TRUE/FALSE), the question I have is why when the flag is true, does the file selection dialog not open? In both cases all lines of code are hit. When I create a file selection dialog in the following manner: `var input = $(document.createElement('input')); input.attr("type", "file"); input.trigger('click');` No hidden elements or wizardry, the same thing occurs. – codephreek May 09 '16 at 22:26
  • 1
    @codephreek jfriend00's answer answers that question. you can't do that outside of a click event. The moment you do something asynchronous, you are outside of that event. – Kevin B May 09 '16 at 22:27
  • @KevinB because I am doing 10 different things at once - I didn't see jfriend00's answer below before replying to you :-) - Thanks for pointing it out! – codephreek May 09 '16 at 22:36

1 Answers1

1

File upload is a feature in a browser that can only be initiated as the direct result of a user action (usually while your JS code is processing a mouse click or keyboard event). It cannot be initiated asynchronously by a timer or via some async callback.

So, when you set your first Ajax call to sync, then your JS click on a hidden element appears to the browser as it is still inside the hidden element click event and thus the upload is allowed. When your first Ajax call is set to async, the user click event is over by the time you try to click the hidden element and the browser will not bring up the upload dialog.

See Trigger click on input=file on asynchronous ajax done() for details.

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979