Pregunta

Tengo una página que permite al usuario descargar un archivo generado dinámicamente. Se necesita mucho tiempo para generar, por lo que me gustaría mostrar un indicador de "espera". El problema es que no puedo encontrar la manera de detectar cuando el navegador ha recibido el archivo, por lo que puede ocultar el indicador.

Estoy haciendo la solicitud en un formulario oculto, qué puestos al servidor, y se dirige a un iframe oculto por sus resultados. Esto es por lo que no sustituir toda la ventana del navegador con el resultado. Escucho para un evento de "carga" en el marco flotante, con la esperanza de que se disparará cuando se complete la descarga.

vuelvo un "Content-Disposition: attachment" encabezado con el archivo, lo que hace que el navegador para mostrar el cuadro de diálogo "Guardar". Pero el navegador no se dispara un evento de "carga" en el marco flotante.

Uno de los enfoques Probé está utilizando una respuesta de varias partes. Por lo que sería enviar un archivo HTML vacío, así como el archivo descargable adjunto. Por ejemplo:

Content-type: multipart/x-mixed-replace;boundary="abcde"

--abcde
Content-type: text/html

--abcde
Content-type: application/vnd.fdf
Content-Disposition: attachment; filename=foo.fdf

file-content
--abcde

Esto funciona en Firefox; que recibe el archivo HTML vacío, se activa el evento de "carga", a continuación, muestra el cuadro de diálogo "Guardar" para el archivo descargable. Pero falla en IE y Safari; IE desencadena el evento "carga", pero no descarga el archivo, y Safari descarga el archivo (con el nombre equivocado y de tipo de contenido), y no se dispara el evento "carga".

Un enfoque diferente podría ser la de hacer una llamada para iniciar la creación del archivo, a continuación, consulte el servidor hasta que esté lista, a continuación, descargue el archivo ya creado. Pero prefiero evitar la creación de archivos temporales en el servidor.

¿Alguien tiene una idea mejor?

¿Fue útil?

Solución

Uno posible solución utiliza JavaScript en el cliente.

El algoritmo de cliente:

  1. Generar un único token aleatorio.
  2. Presentar la solicitud de descarga, e incluir el token en un campo GET / POST.
  3. Mostrar el indicador de "espera".
  4. Iniciar un temporizador, y cada segundo o así, busque una cookie llamada "fileDownloadToken" (o lo que sea que decida).
  5. Si existe la cookie, y su valor coincide con la señal, se oculta el indicador de "espera".

El algoritmo de servidor:

  1. Busque el campo GET / POST en la solicitud.
  2. Si tiene un valor no vacío, la caída de una cookie (por ejemplo "fileDownloadToken"), y establecer su valor en el valor de la ficha.

código fuente de cliente (JavaScript):

function getCookie( name ) {
  var parts = document.cookie.split(name + "=");
  if (parts.length == 2) return parts.pop().split(";").shift();
}

function expireCookie( cName ) {
    document.cookie = 
        encodeURIComponent(cName) + "=deleted; expires=" + new Date( 0 ).toUTCString();
}

function setCursor( docStyle, buttonStyle ) {
    document.getElementById( "doc" ).style.cursor = docStyle;
    document.getElementById( "button-id" ).style.cursor = buttonStyle;
}

function setFormToken() {
    var downloadToken = new Date().getTime();
    document.getElementById( "downloadToken" ).value = downloadToken;
    return downloadToken;
}

var downloadTimer;
var attempts = 30;

// Prevents double-submits by waiting for a cookie from the server.
function blockResubmit() {
    var downloadToken = setFormToken();
    setCursor( "wait", "wait" );

    downloadTimer = window.setInterval( function() {
        var token = getCookie( "downloadToken" );

        if( (token == downloadToken) || (attempts == 0) ) {
            unblockSubmit();
        }

        attempts--;
    }, 1000 );
}

function unblockSubmit() {
  setCursor( "auto", "pointer" );
  window.clearInterval( downloadTimer );
  expireCookie( "downloadToken" );
  attempts = 30;
}

código Ejemplo servidor (PHP):

$TOKEN = "downloadToken";

// Sets a cookie so that when the download begins the browser can
// unblock the submit button (thus helping to prevent multiple clicks).
// The false parameter allows the cookie to be exposed to JavaScript.
$this->setCookieToken( $TOKEN, $_GET[ $TOKEN ], false );

$result = $this->sendFile();

Donde:

public function setCookieToken(
    $cookieName, $cookieValue, $httpOnly = true, $secure = false ) {

    // See: http://stackoverflow.com/a/1459794/59087
    // See: http://shiflett.org/blog/2006/mar/server-name-versus-http-host
    // See: http://stackoverflow.com/a/3290474/59087
    setcookie(
        $cookieName,
        $cookieValue,
        2147483647,            // expires January 1, 2038
        "/",                   // your path
        $_SERVER["HTTP_HOST"], // your domain
        $secure,               // Use true over HTTPS
        $httpOnly              // Set true for $AUTH_COOKIE_NAME
    );
}

Otros consejos

Una solución una línea muy simple (y cojo) es utilizar el evento window.onblur() para cerrar el diálogo de carga. Por supuesto, si se tarda demasiado tiempo y el usuario decide hacer algo más (como correos electrónicos de lectura) el diálogo de carga se cerrará.

hilo viejo, no sé ...

pero aquellos, que se conducen aquí por Google podría estar interesado en mi solución. es muy simple, pero fiable. y hace posible la visualización de mensajes de progreso real (y puede ser conectado fácilmente a los procesos existentes):

el script que procesa (mi problema era: la recuperación de archivos a través de http y entregarlos como zip) escribe el estado de la sesión

.

el estado se sondea y se muestra cada segundo. eso es todo (. bien, no es lo que tiene que hacerse cargo de una gran cantidad de datos [por ejemplo, descargas concurrentes], pero es un buen punto de partida; -)).

la downloadpage:

    <a href="download.php?id=1" class="download">DOWNLOAD 1</a>
    <a href="download.php?id=2" class="download">DOWNLOAD 2</a>
    ...
    <div id="wait">
    Please wait...
    <div id="statusmessage"></div>
    </div>
    <script>
//this is jquery
    $('a.download').each(function()
       {
        $(this).click(
             function(){
               $('#statusmessage').html('prepare loading...');
               $('#wait').show();
               setTimeout('getstatus()', 1000);
             }
          );
        });
    });
    function getstatus(){
      $.ajax({
          url: "/getstatus.php",
          type: "POST",
          dataType: 'json',
          success: function(data) {
            $('#statusmessage').html(data.message);
            if(data.status=="pending")
              setTimeout('getstatus()', 1000);
            else
              $('#wait').hide();
          }
      });
    }
    </script>

getstatus.php

<?php
session_start();
echo json_encode($_SESSION['downloadstatus']);
?>

download.php

    <?php
    session_start();
    $processing=true;
    while($processing){
      $_SESSION['downloadstatus']=array("status"=>"pending","message"=>"Processing".$someinfo);
      session_write_close();
      $processing=do_what_has_2Bdone();
      session_start();
    }
      $_SESSION['downloadstatus']=array("status"=>"finished","message"=>"Done");
//and spit the generated file to the browser
    ?>

i utilizar lo siguiente para descargar gotas y revocar el objeto-url después de la descarga. funciona en Chrome y Firefox!

function download(blob){
    var url = URL.createObjectURL(blob);
    console.log('create ' + url);

    window.addEventListener('focus', window_focus, false);
    function window_focus(){
        window.removeEventListener('focus', window_focus, false);                   
        URL.revokeObjectURL(url);
        console.log('revoke ' + url);
    }
    location.href = url;
}

después de que el cuadro de diálogo de descarga de archivos está cerrada, la ventana obtiene su atención de nuevo por lo que se activa el evento de enfoque.

Me escribió una sencilla clase de JavaScript que implementa una técnica similar a la descrita en bulltorious respuesta. Espero que pueda ser útil a alguien aquí. El proyecto GitHub se llama respuesta monitor.js

Por defecto se utiliza spin.js como el indicador de espera sino que también proporciona un conjunto de devoluciones de llamada para la implementación de un indicador personalizado.

jQuery es compatible, pero no es necesario.

Características notables

  • Integración sencilla
  • No hay dependencias
  • JQuery plug-in (opcional)
  • Spin.js Integración (opcional)
  • devoluciones de llamada configurables para eventos de seguimiento
  • maneja múltiples solicitudes simultáneas
  • del lado del servidor de detección de errores
  • detección Timeout
  • Cruz navegador

Ejemplo de uso

HTML

<!-- the response monitor implementation -->
<script src="response-monitor.js"></script>

<!-- optional JQuery plug-in -->
<script src="response-monitor.jquery.js"></script> 

<a class="my_anchors" href="/report?criteria1=a&criteria2=b#30">Link 1 (Timeout: 30s)</a>
<a class="my_anchors" href="/report?criteria1=b&criteria2=d#10">Link 2 (Timeout: 10s)</a>

<form id="my_form" method="POST">
    <input type="text" name="criteria1">
    <input type="text" name="criteria2">
    <input type="submit" value="Download Report">
</form>

Cliente (normal JavaScript)

//registering multiple anchors at once
var my_anchors = document.getElementsByClassName('my_anchors');
ResponseMonitor.register(my_anchors); //clicking on the links initiates monitoring

//registering a single form
var my_form = document.getElementById('my_form');
ResponseMonitor.register(my_form); //the submit event will be intercepted and monitored

Cliente (JQuery)

$('.my_anchors').ResponseMonitor();
$('#my_form').ResponseMonitor({timeout: 20});

Cliente con devoluciones de llamada (JQuery)

//when options are defined, the default spin.js integration is bypassed
var options = {
    onRequest: function(token){
        $('#cookie').html(token);
        $('#outcome').html('');
        $('#duration').html(''); 
    },
    onMonitor: function(countdown){
        $('#duration').html(countdown); 
    },
    onResponse: function(status){
        $('#outcome').html(status==1?'success':'failure');
    },
    onTimeout: function(){
        $('#outcome').html('timeout');
    }
};

//monitor all anchors in the document
$('a').ResponseMonitor(options);

Server (PHP)

$cookiePrefix = 'response-monitor'; //must match the one set on the client options
$tokenValue = $_GET[$cookiePrefix];
$cookieName = $cookiePrefix.'_'.$tokenValue; //ex: response-monitor_1419642741528

//this value is passed to the client through the ResponseMonitor.onResponse callback
$cookieValue = 1; //for ex, "1" can interpret as success and "0" as failure

setcookie(
    $cookieName,
    $cookieValue,
    time()+300,            // expire in 5 minutes
    "/",
    $_SERVER["HTTP_HOST"],
    true,
    false
);

header('Content-Type: text/plain');
header("Content-Disposition: attachment; filename=\"Response.txt\"");

sleep(5); //simulate whatever delays the response
print_r($_REQUEST); //dump the request in the text file

Para más ejemplos verificar la carpeta ejemplos en el repositorio.

Con base en el ejemplo de Elmer He preparado mi propia solución. Después de hacer clic con elementos definidos descargar clase que permite mostrar mensajes personalizados en la pantalla. He usado enfoque gatillo para ocultar el mensaje.

JavaScript

$(function(){$('.download').click(function() { ShowDownloadMessage(); }); })

function ShowDownloadMessage()
{
     $('#message-text').text('your report is creating, please wait...');
     $('#message').show();
     window.addEventListener('focus', HideDownloadMessage, false);
}

function HideDownloadMessage(){
    window.removeEventListener('focus', HideDownloadMessage, false);                   
    $('#message').hide();
}

HTML

<div id="message" style="display: none">
    <div id="message-screen-mask" class="ui-widget-overlay ui-front"></div>
    <div id="message-text" class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ui-draggable ui-resizable waitmessage">please wait...</div>
</div>

Ahora se debe implementar cualquier elemento de descarga:

<a class="download" href="file://www.ocelot.com.pl/prepare-report">Download report</a>

o

<input class="download" type="submit" value="Download" name="actionType">

Después de cada descargar clic verá el mensaje su informe está creando, por favor espere ...

Si estás reproduciendo un archivo que se está generando dinámicamente, y también tienen una biblioteca de mensajes de servidor a cliente en tiempo real implementado, puede alertar a su cliente con bastante facilidad.

La biblioteca de mensajes de servidor a cliente que me gusta y recomiendo es Socket.io (a través de Node.js). Después de la secuencia de comandos del servidor se realiza la generación del archivo que está siendo transmitido para descargar su última línea en la que el guión puede emitir un mensaje a Socket.io que envía una notificación al cliente. En el cliente, Socket.io escucha los mensajes entrantes emitidos desde el servidor y permite actuar sobre ellos. La ventaja de utilizar este método sobre otros es que son capaces de detectar un evento de acabado "verdadera" después de la transmisión se realiza.

Por ejemplo, se podría mostrar su indicador de ocupado después de hacer clic en un enlace de descarga, transmitir su archivo, emitirá un mensaje a Socket.io desde el servidor en la última línea del script de streaming, escuchar en el cliente para una notificación, recibir la notificación y actualizar la interfaz de usuario al ocultar el indicador de actividad.

Me doy cuenta de la mayoría de la gente que lee las respuestas a esta pregunta podría no tener este tipo de configuración, pero yo he utilizado esta solución exacta con gran efecto en mis propios proyectos y funciona maravillosamente.

Socket.io es increíblemente fácil de instalar y utilizar. Ver más: http://socket.io/

Cuando el usuario activa la generación del archivo, simplemente podría asignar un identificador único a la "descarga", y enviar al usuario a una página que refresca (o cheques con AJAX) cada pocos segundos. Una vez que finaliza el archivo, guardarlo con el mismo ID único y ...

  • Si el archivo está listo, hacer la descarga.
  • Si el archivo no está listo, mostrar el progreso.

A continuación, se puede omitir el conjunto de marco flotante / desorden de espera / browserwindow, sin embargo, tener una solución muy elegante.

Si no desea generar y almacenar el archivo en el servidor, ¿está dispuesto para almacenar el estado, por ejemplo, presentar en curso, archivos completa? Su "espera" página podría sondear el servidor para saber cuando la generación del archivo. Usted no sabe con seguridad que el navegador inicia la descarga, pero usted tendría algo de confianza.

Estoy muy tarde a la fiesta, pero voy a poner esto aquí si alguien más le gustaría saber mi solución:

Yo tenía una verdadera lucha con este problema exacto, pero he encontrado una solución viable mediante iframes (lo sé, lo sé. Es terrible pero funciona para un problema simple que tuve)

Yo tenía una página HTML que puso en marcha un script php independiente que genera el archivo y lo descargó. En la página html, he utilizado la siguiente jQuery en la cabecera HTML (que tendrá que incluir una biblioteca jQuery también):

<script>
    $(function(){
        var iframe = $("<iframe>", {name: 'iframe', id: 'iframe',}).appendTo("body").hide();
        $('#click').on('click', function(){
            $('#iframe').attr('src', 'your_download_script.php');
        });
        $('iframe').load(function(){
            $('#iframe').attr('src', 'your_download_script.php?download=yes'); <!--on first iframe load, run script again but download file instead-->
            $('#iframe').unbind(); <!--unbinds the iframe. Helps prevent against infinite recursion if the script returns valid html (such as echoing out exceptions) -->
        });
    });
</script>

En your_download_script.php, tener lo siguiente:

function downloadFile($file_path) {
    if (file_exists($file_path)) {
        header('Content-Description: File Transfer');
        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename=' . basename($file_path));
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file_path));
        ob_clean();
        flush();
        readfile($file_path);
        exit();
    }
}


$_SESSION['your_file'] = path_to_file; //this is just how I chose to store the filepath

if (isset($_REQUEST['download']) && $_REQUEST['download'] == 'yes') {
    downloadFile($_SESSION['your_file']);
} else {
    *execute logic to create the file*
}

Para descomponerlo, jQuery lanza primero el script php en un iframe. El iframe se carga una vez se genera el archivo. Entonces jQuery lanza el script de nuevo con una variable de petición diciendo la secuencia de comandos para descargar el archivo.

La razón de que no se puede hacer la descarga y la generación de archivos de una sola vez es debido a la función header () php. Si utiliza la cabecera (), que está cambiando el guión a algo distinto de una página web y jQuery nunca reconocerá el script descarga como ser 'cargado'. Sé que esto no necesariamente puede estar detectando cuando un navegador recibe un archivo, pero su problema sonaba similar a la mía.

Sólo tenía este mismo problema. Mi solución fue usar los archivos temporales desde que estaba generando un montón de archivos temporales ya. Este formulario se envía con:

var microBox = {
    show : function(content) {
        $(document.body).append('<div id="microBox_overlay"></div><div id="microBox_window"><div id="microBox_frame"><div id="microBox">' +
        content + '</div></div></div>');
        return $('#microBox_overlay');
    },

    close : function() {
        $('#microBox_overlay').remove();
        $('#microBox_window').remove();
    }
};

$.fn.bgForm = function(content, callback) {
    // Create an iframe as target of form submit
    var id = 'bgForm' + (new Date().getTime());
    var $iframe = $('<iframe id="' + id + '" name="' + id + '" style="display: none;" src="about:blank"></iframe>')
        .appendTo(document.body);
    var $form = this;
    // Submittal to an iframe target prevents page refresh
    $form.attr('target', id);
    // The first load event is called when about:blank is loaded
    $iframe.one('load', function() {
        // Attach listener to load events that occur after successful form submittal
        $iframe.load(function() {
            microBox.close();
            if (typeof(callback) == 'function') {
                var iframe = $iframe[0];
                var doc = iframe.contentWindow.document;
                var data = doc.body.innerHTML;
                callback(data);
            }
        });
    });

    this.submit(function() {
        microBox.show(content);
    });

    return this;
};

$('#myForm').bgForm('Please wait...');

Al final de la secuencia de comandos que genera el archivo que tengo:

header('Refresh: 0;url=fetch.php?token=' . $token);
echo '<html></html>';

Esto hará que el evento de carga en el iframe para ser disparado. A continuación, el mensaje de espera se cierra y el archivo de descarga continuación, se iniciará. Probado en IE7 y Firefox.

Si usted tiene descargar un archivo, que se guarda, en lugar de ser en el documento, no hay manera de determinar cuándo se completa la descarga, ya que no está en el ámbito del documento actual, sino un proceso separado en el navegador.

"¿Cómo detectar cuando el navegador recibe archivo de descarga?"
me enfrenté al mismo problema con esa configuración:
puntales 1.2.9
jquery-1.3.2.
jquery-ui-1.7.1.custom
IE 11
java 5


Mi solución con una galleta:
- Del lado del cliente:
Al presentar su formulario, llame a su función javascript para ocultar su página y cargar el spinner de espera

function loadWaitingSpinner(){
... hide your page and show your spinner ...
}

A continuación, llamar a una función que comprobará cada 500 ms si una cookie está llegando desde el servidor.

function checkCookie(){
    var verif = setInterval(isWaitingCookie,500,verif);
}

Si no se encuentra la cookie, dejar de revisar cada 500 ms, la cookie expirará y llame a su función para volver a la página y quitar el spinner en espera ( removeWaitingSpinner () ). Es importante expira la cookie si desea ser capaz de descargar otro archivo de nuevo!

function isWaitingCookie(verif){
    var loadState = getCookie("waitingCookie");
    if (loadState == "done"){
        clearInterval(verif);
        document.cookie = "attenteCookie=done; expires=Tue, 31 Dec 1985 21:00:00 UTC;";
        removeWaitingSpinner();
    }
}
    function getCookie(cookieName){
        var name = cookieName + "=";
        var cookies = document.cookie
        var cs = cookies.split(';');
        for (var i = 0; i < cs.length; i++){
            var c = cs[i];
            while(c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) == 0){
                return c.substring(name.length, c.length);
            }
        }
        return "";
    }
function removeWaitingSpinner(){
... come back to your page and remove your spinner ...
}

- Del lado del servidor:
Al final de su proceso de servidor, añadir una cookie para la respuesta. Esa cookie se envía al cliente cuando su archivo estará disponible para su descarga.

Cookie waitCookie = new Cookie("waitingCookie", "done");
response.addCookie(waitCookie);

Espero poder ayudar a alguien!

La cuestión es tener un indicador de ‘espera’ mientras se genera un archivo y luego volver a la normalidad una vez que el archivo se descarga. La forma en que me gusta TODO esto es usar un iframe oculto y enganche proceso de carga de la estructura para permitir que mi página de descarga sabe cuándo comienza. y onload no se dispara en el IE para la descarga de archivos (como con el token encabezado del archivo adjunto). Sondeo el servidor funciona, pero no me gusta la complejidad adicional. Así que aquí es lo que hago:

  • Objetivo para el iframe oculto como de costumbre.
  • Generar el contenido. Almacenar en caché con un tiempo de espera absoluta en 2 minutos.
  • Enviar un redireccionamiento de JavaScript de nuevo a el cliente llamando, llamando esencialmente el generador de la página por segunda vez. NOTA:. Esto hará que el proceso de carga de fuego en el IE, ya que está actuando como una página normal
  • Eliminar el contenido de la memoria caché y enviarlo al cliente.

Aviso Legal, no hagas esto en un sitio ocupado, debido al almacenamiento en caché podría sumar. Pero en realidad, si los sitios que ocupada el proceso de larga duración que se morirán de hambre de hilos de todos modos.

Esto es lo que el código subyacente parece, que es todo lo que realmente necesita.

public partial class Download : System.Web.UI.Page
{
    protected System.Web.UI.HtmlControls.HtmlControl Body;

    protected void Page_Load( object sender, EventArgs e )
    {
        byte[ ] data;
        string reportKey = Session.SessionID + "_Report";

        // Check is this page request to generate the content
        //    or return the content (data query string defined)
        if ( Request.QueryString[ "data" ] != null )
        {
            // Get the data and remove the cache
            data = Cache[ reportKey ] as byte[ ];
            Cache.Remove( reportKey );

            if ( data == null )                    
                // send the user some information
                Response.Write( "Javascript to tell user there was a problem." );                    
            else
            {
                Response.CacheControl = "no-cache";
                Response.AppendHeader( "Pragma", "no-cache" );
                Response.Buffer = true;

                Response.AppendHeader( "content-disposition", "attachment; filename=Report.pdf" );
                Response.AppendHeader( "content-size", data.Length.ToString( ) );
                Response.BinaryWrite( data );
            }
            Response.End();                
        }
        else
        {
            // Generate the data here. I am loading a file just for an example
            using ( System.IO.FileStream stream = new System.IO.FileStream( @"C:\1.pdf", System.IO.FileMode.Open ) )
                using ( System.IO.BinaryReader reader = new System.IO.BinaryReader( stream ) )
                {
                    data = new byte[ reader.BaseStream.Length ];
                    reader.Read( data, 0, data.Length );
                }

            // Store the content for retrieval              
            Cache.Insert( reportKey, data, null, DateTime.Now.AddMinutes( 5 ), TimeSpan.Zero );

            // This is the key bit that tells the frame to reload this page 
            //   and start downloading the content. NOTE: Url has a query string 
            //   value, so that the content isn't generated again.
            Body.Attributes.Add("onload", "window.location = 'binary.aspx?data=t'");
        }
    }

Una solución rápida si sólo desea visualizar un mensaje o un gif cargador hasta que se muestre el diálogo de descarga es poner el mensaje en un contenedor oculto y al hacer clic en el botón que genera el archivo que desea descargar a sacar el contenedor visible. A continuación, utilice o jQuery JavaScript para capturar el evento focusOut del botón para ocultar el recipiente que contiene el mensaje

Si XMLHTTPRequest con gota no es una opción, entonces puede abrir el archivo en una nueva ventana y comprobar si los elementos eny son rellenados en ese cuerpo ventana con intervalo.

var form = document.getElementById("frmDownlaod");
 form.setAttribute("action","downoad/url");
 form.setAttribute("target","downlaod");
 var exportwindow = window.open("", "downlaod", "width=800,height=600,resizable=yes");
 form.submit();

var responseInterval = setInterval(function(){
	var winBody = exportwindow.document.body
	if(winBody.hasChildNodes()) // or 'downoad/url' === exportwindow.document.location.href
	{
		clearInterval(responseInterval);
		// do your work
		// if there is error page configured your application for failed requests, check for those dom elemets 
	}
}, 1000)
//Better if you specify maximun no of intervals

Crear un iframe cuando se hace clic en el botón / enlace y añadir esto a cuerpo.

                  $('<iframe />')
                 .attr('src', url)
                 .attr('id','iframe_download_report')
                 .hide()
                 .appendTo('body'); 

Crear un iframe con retraso y eliminarlo después de la descarga.

                            var triggerDelay =   100;
                            var cleaningDelay =  20000;
                            var that = this;
                            setTimeout(function() {
                                var frame = $('<iframe style="width:1px; height:1px;" class="multi-download-frame"></iframe>');
                                frame.attr('src', url+"?"+ "Content-Disposition: attachment ; filename="+that.model.get('fileName'));
                                $(ev.target).after(frame);
                                setTimeout(function() {
                                    frame.remove();
                                }, cleaningDelay);
                            }, triggerDelay);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top