Login Register

Using dojo.io.iframe.send to download a file as an attachment has a problem

I have a web page with a button. When the user clicks the button I would like to download a csv file from the server to the client without changing the current document location. This best way I think to do this is using an IFRAME via dojo.io.iframe.send. Unfortunately it seems dojo.io.iframe.send doesn't completely support this.

My server sets the content type as text/csv and also the "Content-disposition" header as "attachment; filename=myfile.csv". What I would like is for a dialog to appear to prompt the user to open or save the file.

This does happen the first time, but i've noticed the load handler never gets called and I can't do any more downloads using the dojo.io.iframe.send method. I think this is because dojo doesn't recogize when the file has finished downloading because its looking for a textarea or something to be in the respone text. I can't put a textarea in the response because this would then corrupt the CSV file.

I think dojo needs to support downloading file attachments via iframes. If it already does this, can someone tell me what I'm doing wrong. My code is below...

onDownloadCsvClick: function() {
                // get the current url of the grid.
                console.log("Starting GridToobar.onDownloadCsvClick(", arguments, ")...");
                if (this.grid && this.store) {

                        console.log("performing download...");
                        // TODO: make downloading as a file a store function?

                        console.log("this.store = ", this.store);
                        var url = this.store.url.replace(/\/Admin\//, "/Export/"); ;
                        url += ".csv";
               
                        var getArgs = {
                                method: "GET",
                                url: url,
                                content: {},
                                handleAs: "html",
                                load: dojo.hitch(this, "onDownloadComplete"),
                                error: dojo.hitch(this, "onDownloadError")
                        }

                        this.store._setQueryContent(getArgs.content, this.grid.query);
                        this.store._setSortContent(getArgs.content, this.grid.sortFields);

                        console.log("getArgs: ", getArgs);
               
                        // do an IFrame request to download the csv file.
                        dojo.io.iframe.send(getArgs);
                }
                console.log("Finished GridToobar.onDownloadCsvClick()" );
        },

        onDownloadXmlClick: function() {
        },

        onDownloadComplete: function(data, ioargs) {
                console.log("Starting GridToolbar.onDownloadComplete(", arguments, ")...");
                alert("Download successfully completed!");
                console.log("Finished GridToolbar.onDownloadComplete()");
        },

        onDownloadError: function(error, ioargs) {
                console.log("Starting GridToolbar.onDownloadError(", arguments, ")...");
                var xhr = ioargs.xhr;
                var response = xhr.responseText;
                var contentType = xhr.getResponseHeader("Content-Type");
                alert( "Download Error: " + response );
                if ( contentType == "text/json" || contentType == "application/json" ) {
                        response = dojo.eval('(' + response + ')');
                }
               
                console.log("Finished GridToolbar.onDownloadError()");
        }

yep. So in order for an

yep.

So in order for an iframe.io (x-domain only iirc) to fire it's load: callback, it needs to find a TEXTAREA tag in the response text. by giving the target a url that will pop up a save as dialog, you are effectively breaking any chance of any load callback (that url can't return a .zip file AND an html segment). I've worked around this by setting a timeout: param of "whatever i assume the worse possible latency will be to trigger the download", and register an error: function to handle the timeout should it occur. (otherwise assume it went okay, as the xhr bit of the iframe goes and does it's thing).

hope this helps.

So there's no value in using dojo.io.iframe.send

Thanks for your input. At least I know i wasn't misusing dojo.io.iframe.send.

I may as well just create my own iframe and just change the src attribute to the url I want to download. I've done a quick implementation of this and it seems to work ok. Seems simpler than making dojo.io.iframe.send timeout the request.

Small clarification on

Small clarification on dante's post: it is not xdomain concerns that require the textarea in an HTML response, but rather Safari not firing the onload event unless the response was an HTML document. This was an issue for Safari 2, but it may not be an issue for Safari 3 (needs more testing).

BTW, in the xdomain case, the response format really will not matter since the browser's same origin policy will block access to the frame content.