2014-09-26 17 views
5

Ho scritto una direttiva basata su Scott's answer. Usereste in questo modo:Download dinamico di AngularJs dalla risposta

<button class="btn btn-success" 
     download-response="getData()" 
     download-success="getDataSuccess()" 
     download-error="getDataError()" 
     download-name="{{name}}.pdf" 
     download-backup-url="/Backup/File.pdf"> 
    Save 
</button> 

Problema: il codice qui sotto genera un errore TypeError: Invalid calling object nel IE11 sul primo metodo (linea: saveBlob(blob, filename);). Anche se ricade su altri metodi di download, sono a conoscenza del fatto che il metodo saveMethod1 dovrebbe funzionare in IE11.

Ecco il codice:

'use strict'; 

// directive allows to provide a function to be executed to get data to be downloaded 
// attributes: 
// download-response - Required. Function to get data. It must return a promise. It must be declared on the $scope. 
// download-success - Optional. Function to be executed if download-response function was successfully resolved. It must be declared on the $scope. 
// download-error - Optional. Function to be executed if download-response function return a promise rejection. It must be declared on the $scope. 
// download-mime - Optional. provide a mime type of data being downloaded. Defaulted to "application/octet-stream" 
// download-name - Optional. name of the file to download. Defaulted to "download.bin" 
// download-backup-url - in case browser does not support dynamic download, this url will be called to get the file 
angular.module('app.directives') 
    .directive('downloadResponse', [ '$parse', '$timeout', 
     function ($parse, $timeout) { 

      function saveMethod1(data, filename, contentType) { 
       // Support for saveBlob method (Currently only implemented in Internet Explorer as msSaveBlob, other extension in case of future adoption) 
       var saveBlob = navigator.msSaveBlob || navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob; 

       if (saveBlob) { 
        // Save blob is supported, so get the blob as it's contentType and call save. 
        var blob = new Blob([data], { type: contentType }); 
        saveBlob(blob, filename); 
        //console.log("SaveBlob Success"); 
       } else { 
        throw 'saveBlob is not supported. Falling back to the next method'; 
       } 
      } 

      function saveMethod2(data, filename, contentType, octetStreamMime) { 
       // Get the blob url creator 
       var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL; 
       if (urlCreator) { 
        // Try to use a download link 
        var link = document.createElement("a"); 
        var url; 
        if ("download" in link) { 
         // Prepare a blob URL 
         var blob = new Blob([data], { type: contentType }); 
         url = urlCreator.createObjectURL(blob); 
         link.setAttribute("href", url); 

         // Set the download attribute (Supported in Chrome 14+/Firefox 20+) 
         link.setAttribute("download", filename); 

         // Simulate clicking the download link 
         var event = document.createEvent('MouseEvents'); 
         event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null); 
         link.dispatchEvent(event); 

         //console.log("Download link Success"); 
        } else { 
         // Prepare a blob URL 
         // Use application/octet-stream when using window.location to force download 
         var blob = new Blob([data], { type: octetStreamMime }); 
         url = urlCreator.createObjectURL(blob); 
         window.location = url; 

         //console.log("window.location Success"); 
        } 
       } else { 
        throw 'UrlCreator not supported. Falling back to the next method'; 
       } 
      } 

      function saveMethod3(attrs) { 
       if (attrs.downloadBackupUrl && attrs.downloadBackupUrl != '') { 
        console.log('opening ' + attrs.downloadBackupUrl); 
        window.open('http://' + document.domain + attrs.downloadBackupUrl, '_blank'); 
       } else { 
        throw 'Could not download a file using any of the available methods. Also you did not provide a backup download link. No more bullets left...'; 
       } 
      } 

      return { 
       restrict: 'A', 
       scope: false, 
       link:function (scope, elm, attrs) { 
        var getDataHandler = $parse(attrs.downloadResponse); 

        elm.on('click', function() { 
         var promise = getDataHandler(scope); 
         promise.then(
          function (data) { 
           if (attrs.downloadSuccess && attrs.downloadSuccess != '') { 
            var successHandler = $parse(attrs.downloadSuccess); 
            successHandler(scope); 
           } 

           var octetStreamMime = "application/octet-stream"; 

           var filename = attrs.downloadName || "download.bin"; 
           var contentType = attrs.downloadMime || octetStreamMime; 


           try { 
            saveMethod1(data, filename, contentType); 
            return; 
           } catch (e) { 
            console.log(e); 
            try { 
             saveMethod2(data, filename, contentType, octetStreamMime); 
             return; 
            } catch (e) { 
             console.log(e); 
             try { 
              saveMethod3(attrs); 
              return; 
             } catch (e) { 
              throw e; 
             } 
             throw e; 
            } 
            throw e; 
           } 
          }, 
          function(data) { 
           if (attrs.downloadError && attrs.downloadError != '') { 
            var errorHandler = $parse(attrs.downloadError); 
            errorHandler(scope); 
           } 
          } 
         ); 
        }); 

       } 
      }; 
     } 
    ]); 

Ogni aiuto è molto apprezzato!

+0

Dmitry hai avuto la possibilità di provare la soluzione IE11? – Scott

+0

Scusa se non ho avuto la possibilità di confermare questo funziona. Ho questa domanda aperta in una scheda separata perché so che ci tornerò molto presto. Ti darò un feedback una volta che darò uno scatto. Apprezzo che tu abbia esaminato il problema! – Dmitry

+0

Non preoccuparti :) Grazie – Scott

risposta

5

Problema:

ho risolto questo problema. Sembra che Internet Explorer 11 non piace alias alla funzione msSaveBlob, dimostrato dagli esempi più semplici:

// Succeeds 
navigator.msSaveBlob(new Blob(["Hello World"]), "test.txt"); 

// Fails with "Invalid calling object" 
var saveBlob = navigator.msSaveBlob; 
saveBlob(new Blob(["Hello World"]), "test.txt"); 

Quindi, in sostanza l'alias generico creato per incapsulare saveBlob funzionalità, che dovrebbe essere consentita, impedisce msSaveBlob di lavorare come previsto :

var saveBlob = navigator.msSaveBlob || navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob; 

Soluzione:

Così il lavoro intorno è quello di testare per msSaveBlob separatamente.

if(navigator.msSaveBlob) 
    navigator.msSaveBlob(blob, filename); 
else { 
    // Try using other saveBlob implementations, if available 
    var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob; 
    if(saveBlob === undefined) throw "Not supported"; 
    saveBlob(blob, filename); 
} 

tl; dr

Quindi il metodo msSaveBlob funziona, a patto che non si alias funzioni. Forse è una precauzione di sicurezza - ma allora forse un'eccezione di sicurezza sarebbe stata più appropriata, anche se penso che sia molto probabilmente un difetto, considerando la fonte. :)

+1

questo ha funzionato alla grande! Grazie per la tua ricerca – Dmitry

+0

@Dmitry Grande, felice ha funzionato. :) – Scott

+0

@Scott, andando a prendere da qui solo in I.E 11, var blob = new Blob ([data], {type: contentType}); – cracker

Problemi correlati