10

Internet Explorer (with default settings, which I generally assume will be in effect on the desktops of the Great Unwashed) seems to dislike the idea of accepting attachment content in an HTTP response if the corresponding request wasn't made directly from a user action (like a "click" handler, or a native form submit). There are probably more details and nuances, but that's the basic behavior that's frustrating me.

It seems to me that this situation is common: the user interface in front of some downloadable content — say, a prepared PDF report — allows for some options and inputs to be used in the creation of the content. Now, as with all forms that allow the user to stipulate how an application does something, it's possible that the input will be erroneous. Not always, but sometimes.

Thus there's a dilemma. If the client tries to do something fancy, like run an AJAX transaction to let the server vet the form contents, and then resubmit to get the download, IE won't like that. It won't like it because the actual HTTP transaction that carries the attachment back will happen not in the original user-action event handler, but in the AJAX completion callback. Worse, since the IE security bar seems to think that the solution to all one's problems is to simply reload the outer page from its original URL, its invitation to the user to go ahead and download the suspicious content won't even work.

The other option is to just have the form fire away. The server checks the parameters, and if there's anything wrong it responds with the form-container page, peppered appropriately with error messages. If the form contents are OK, it generates the content and ships it back in the HTTP response as an attached file. In this case (I think), IE is happy because the content was apparently directly requested by the user (which is, by the way, a ridiculously flimsy way to tell good content from bad content). This is great, but the problem now is that the client environment (that is, the code on my page) can't tell that the download worked, so the form is still just sitting there. If my form is in some sort of dialog, then I really need to close that up when the operation is complete — really, that's one of the motivations for doing it the AJAX way.

It seems to me that the only thing to do is equip the form dialogs with messaging that says something like, "Close this when your download begins." That really seems lame to me because it's an example of a "please push this button for me" interface: ideally, my own code should be able to push the buutton when it's appropriate. A key thing that I don't know is whether there's any way for client code to detect that form submission has resulted in an attachment download. I've never heard of a way to detect that, but that'd break the impasse for me.

Pointy
  • 405,095
  • 59
  • 585
  • 614

3 Answers3

8

I take it you're submitting the form with a different target window; hence the form staying in place.

There are several options.

  1. Keep the submit button disabled and do ongoing validation in the background, polling the form for changes to fields and then firing off the validation request for a field as it changes. When the form is in a valid state, enable the button; when it isn't, disable the button. This isn't perfect, as there will tend to be a delay, but it may be good enough for whatever you're doing.
  2. Do basic validation that doesn't require round-trips to the server in a handler for the form's submit event, then submit the form and remove it (or possibly just hide it). If the further validation on the server detects a problem, it can return a page that uses JavaScript to tell the original window to re-display the form.
  3. Use a session cookie and a unique form ID (the current time from new Date().getTime() would do); when the form is submitted, disable its submit button but keep it visible until the response comes back. Make the response set a session cookie with that ID indicating success/failure. Have the window containing the form poll for the cookie every second or so and act on the result when it sees it. (I've never done this last one; not immediately seeing why it wouldn't work.)

I expect there are about a dozen other ways to skin this cat, but those are three that came to mind.

(Edit) If you're not submitting to a different target, you might want to go ahead and do that -- to a hidden iframe on the same page. That (possibly combined with the above or other answers) might help you get the user experience you're looking for.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • No, when you submit a form and the response is an attachment (that is, a file to download) the browser does not repaint the page. – Pointy Jan 14 '10 at 15:04
  • That last one looks like a really good idea! I wonder if the cookie would get set successfully if the download fails. Brilliant idea whether it works or not! – Graza Jan 14 '10 at 15:05
  • @Pointy: Ah, okay, it did seem a bit weird. I think these basic ideas could be adapted to what you're doing, but without being deep in the guts of it... @Graza: That's kind. I don't think I'd call it "brilliant" if it doesn't work, but thanks. :-) – T.J. Crowder Jan 14 '10 at 15:10
  • The cookie idea is truly awesome, now that I've allowed it to penetrate the stagnant fat layer around my head. The technique shall be called the Crowder Cookie Trick. – Pointy Jan 14 '10 at 15:17
  • @T.J. - I meant the idea was good. It's thinking outside the box, which you need to do a lot to get around the walls we hit in web development. Some ideas work, some don't - but just because they don't it doesn't mean they weren't good ideas – Graza Jan 14 '10 at 15:19
  • @T.J. Crowder Where did you get idea number three? I think it is generally excepted that this problem is can only be solved through number 1. – GC_ Feb 14 '12 at 22:35
  • 1
    @Grae: I came up with it for this answer -- and immediately turned around and used it on a project. Works a treat. In my case I use this technique to show a "Building..." modal dialog box (div) when the user requests a custom PDF from the server. The form submits to a hidden iframe, and then my code polls for the cookie. All being well, the response comes back with `Content-Disposition: attachment`, popping up the download box; my code sees the cookie and closes the modal. If there's an error, my code sees the error in the cookie and shows it to the user. I really must blog this w/a demo. :-) – T.J. Crowder Feb 15 '12 at 06:50
2

There's a whole number of really good reasons IE does this, and I'm sure it's not something anyone would argue with - so the main objective is to get around it somehow to make things better for your users.

Sometimes its worth re-thinking how things are done. Perhaps disable the button, use javascript to check when all the fields are filled out, and fire off an ajax request once they are. If the ajax was successful, enable the button. This is but one suggestion, I'm sure there will be more...

Edit: more...

Do simple submission (non-AJAX), and if the checks fail, send a page back rather than an attachment. The page sent back could contain all the information originally submitted (plus whatever error message to the user) so the user doesn't need to fill out the entire form again. And I'm also sure there will be more ideas...

Edit: more...

I'm sure you've seen this type of thing before - and yes, it is an extra click (not ideal, but not hard).... an "if your download fails, click here" -> in this case, do it as you want to do it, but add a new link/button to the page when the AJAX returns, so if the download failed, they can submit the already validated form from a "direct user action". And I'm sure I'll think of more (or someone else will).....

Graza
  • 5,010
  • 6
  • 32
  • 37
  • Well I agree that IE does this for "good" reasons, but to a large extent those reasons involve other system software not being very smart. Note that Firefox and Safari and Chrome don't have this problem, and to my knowledge that's not considered a significant security exposure. – Pointy Jan 14 '10 at 15:06
1

I have been fighting a similar issue for a while. In my case, posting to a hidden iframe didn't work if my web app was embedded in an iframe on another site (third party cookie issues) unless our site was added to the Trusted Sites list.

I have found that I could break up the download into POST and GET sequence. The post returns a short lived GUID that can be used in a GET request to initiate the download. The POST can do the form validation as well as return the GUID in a successful response. Once the client has the GUID, you can set the src property of a hidden iframe element to the download URL. The browser sees the 'Content-Disposition': 'attachement' header and gives the user a download ribbon to download the file.

So far it appears to work in all the latest browsers. Unfortunately it requires you to modify you server side API for downloading the file.

Doug Coburn
  • 2,485
  • 27
  • 24
  • That works fine, but seriously the "cookie trick" is a secure and reliable way to make the interaction work. – Pointy Dec 11 '17 at 21:39
  • @Pointy I really like the cookie trick and I'm sure it will work great for you. I tried it, but like I said, I need downloads to work in IE11 when the web app is running in an iframe hosted by a third party. The cookie part works, but IE will eat the download ribbon if I try to post a form to a hidden iframe. -- I just added my answer in case someone may find it useful. – Doug Coburn Dec 11 '17 at 22:54
  • 1
    Yes OK that may make a big difference. My site is pretty vanilla. – Pointy Dec 11 '17 at 22:56