2014-09-26 88 views
5

我寫了一個基於Scott's answer的指令。你會使用它像這樣:AngularJs動態下載回覆

<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> 

問題:下面的代碼拋出一個錯誤TypeError: Invalid calling objectIE11在第一種方法(行:saveBlob(blob, filename);)。儘管它回落到其他下載方法,但我的理解是saveMethod1應該在IE11中工作。

下面是代碼:

'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); 
           } 
          } 
         ); 
        }); 

       } 
      }; 
     } 
    ]); 

任何幫助,不勝感激!

+0

德米特里你有機會嘗試IE11的變通? – Scott 2014-10-13 16:25:48

+0

對不起,我沒有機會確認這件作品。我在單獨的選項卡中打開了這個問題,因爲我知道我很快就會回到這個問題。一旦我給了這個鏡頭,我會給你反饋。我很感激你看着這個問題! – Dmitry 2014-10-13 16:54:40

+0

不用擔心:)謝謝 – Scott 2014-10-13 16:56:10

回答

5

問題:

我已解決此問題。看來,互聯網瀏覽器11不喜歡別名爲msSaveBlob功能,通過最簡單的例子證明:

// 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"); 

所以基本上創建封裝saveBlob功能,這應該是允許的,通用的別名防止msSaveBlob按預期工作:

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

解決方法:

因此,解決辦法是單獨測試msSaveBlob

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;博士

所以msSaveBlob方法的工作,只要你不別名功能。也許這是一個安全預防措施 - 但後來可能安全例外會更合適,但我認爲這很可能是一個缺陷,考慮到來源。 :)

+1

這個效果很好!感謝您的研究 – Dmitry 2014-10-20 20:43:32

+0

@Dmitry很好,很高興它的工作。 :) – Scott 2014-10-21 10:03:47

+0

@Scott,只能在I.E 11中進入catch,var blob = new Blob([data],{type:contentType}); – cracker 2016-08-31 06:16:20