<!doctype html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta charset="UTF-8">
  <title>Example - example-directive-simple-production</title>
  <script>
    var userAgent = navigator.userAgent.toLowerCase();
    console.log(userAgent);
  </script>
  <script data-require="angular.js@1.7.9" src="http://code.angularjs.org/1.7.9/angular.js" data-semver="1.7.9"></script>
  <script src="./script.js"></script>  
</head>
<body>
  <style>
    .buttonStyle {
      font-size: 250%;
      background: azure !important;
    }
  </style>
<div ng-app="fileDownloaderModule">
  <div ng-controller="dataController">
    <div style="padding: 5px;display: flex; width: 100%, flex-wrap: wrap; font-size: 200%; background-color:#ddff00;font-family: Arial, Helvetica, sans-serif;">
      <div style="padding: 5px; width: 50%">Open in current window</div>  
      <div style="padding: 5px; width: 50%">Open  in new Window</div>
    </div>
    <div style="padding: 5px; background-color:#ccffcc">
      <div style="display: flex; width: 100%, flex-wrap: wrap">
        
        <div style="padding: 5px; width: 50%">
          <file-downloader button-class="buttonStyle" caption="Download csv file" content-type="text/csv;charset=utf-8;" filename="file.csv" data="loadCvsData()" icon-class=''>
          </file-downloader>  
          <hr style="background-color: red; height: 3px; border: 0;">
          <file-downloader button-class="buttonStyle" caption="Download csv file" content-type="text/plain" filename="file.csv" data="loadCvsData()" icon-class=''>
          </file-downloader>  
          <hr style="background-color: red; height: 3px; border: 0;">
          <file-downloader button-class="buttonStyle" caption="Download csv file" content-type="application/octet-stream" filename="file.csv" data="loadCvsData()" icon-class=''>
          </file-downloader>
        </div>

        <div style="padding: 5px; width: 50%">
          <file-downloader button-class="buttonStyle" caption="Download csv file" content-type="text/csv;charset=utf-8;" filename="file.csv" data="loadCvsData()" icon-class='' new-window='true'>
          </file-downloader>  
          <hr style="background-color: red; height: 3px; border: 0;">
          <file-downloader button-class="buttonStyle" caption="Download csv file" content-type="text/plain" filename="file.csv" data="loadCvsData()" icon-class='' new-window='true'>
          </file-downloader>  
          <hr style="background-color: red; height: 3px; border: 0;">
          <file-downloader button-class="buttonStyle" caption="Download csv file" content-type="application/octet-stream" filename="file.csv" data="loadCvsData()" icon-class='' new-window='true'>
          </file-downloader>
        </div>        

      </div>
    </div>
    <hr style="height: 10px; visibility: hidden;">
    
    <div style="background-color:#fff2cc">
      <div style="display: flex; width: 100%, flex-wrap: wrap">
        <div style="padding: 5px; width: 50%">
          <file-downloader button-class="buttonStyle" caption="Download pdf file" content-type="application/pdf" filename="file.pdf" data="loadPdfData()">
          </file-downloader>
          <hr style="background-color: red; height: 3px; border: 0;"> 
          <file-downloader button-class="buttonStyle" caption="Download pdf file" content-type="application/octet-stream" filename="file.pdf" data="loadPdfData()">
          </file-downloader>
        </div>  
        
        <div style="padding: 5px; width: 50%">
          <file-downloader button-class="buttonStyle" caption="Download Pdf file" content-type="application/pdf" filename="file.pdf" data="loadPdfData()"  new-window='true'>
          </file-downloader>
          <hr style="background-color: red; height: 3px; border: 0;"> 
          <file-downloader button-class="buttonStyle" caption="Download pdf file" content-type="application/octet-stream" filename="file.pdf" data="loadPdfData()"  new-window='true'>
          </file-downloader>
        </div>
      </div>      
    </div>    
  </div>
</div>
</body>
</html>
'use strict';

function dataFilesDummyData() {
    function getCsvData(){
      return 'RGF0ZSxBbW91bnQsRGVzY3JpcHRpb24NCjA1LzAxLzIwMjAsIiQxLDU4Ni4wOSIsUGF5bWVudCBBbW91bnQNCjA0LzAyLzIwMjAsIiQxLDU4Ni4wOSIsUGF5bWVudCBBbW91bnQNCjAzLzAyLzIwMjAsIiQxLDU4Ni4wOSIsUGF5bWVudCBBbW91bnQNCjAxLzMxLzIwMjAsIiQxLDU4Ni4wOSIsUGF5bWVudCBBbW91bnQNCjAxLzAyLzIwMjAsIiQxLDU4Ni4wOSIsUGF5bWVudCBBbW91bnQNCjEyLzA3LzIwMTksIiQxLDU4Ni4wOSIsUGF5bWVudCBBbW91bnQNCjExLzAyLzIwMTksIiQxLDU4Ni4wOSIsUGF5bWVudCBBbW91bnQNCjEwLzAxLzIwMTksIiQxLDU4Ni4wOSIsUGF5bWVudCBBbW91bnQNCjA5LzAyLzIwMTksIiQxLDU4Ni4wOSIsUGF5bWVudCBBbW91bnQNCjA4LzAzLzIwMTksIiQxLDU4Ni4wOSIsUGF5bWVudCBBbW91bnQ=';
    };

    function getPdfData(){
      return 'JVBERi0xLjINJeLjz9MNCjMgMCBvYmoNPDwgDS9MaW5lYXJpemVkIDEgDS9PIDUgDS9IIFsgNzYwIDE1NyBdIA0vTCAzOTA4IA0vRSAzNjU4IA0vTiAxIA0vVCAzNzMxIA0+PiANZW5kb2JqDSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4cmVmDTMgMTUgDTAwMDAwMDAwMTYgMDAwMDAgbg0KMDAwMDAwMDY0NCAwMDAwMCBuDQowMDAwMDAwOTE3IDAwMDAwIG4NCjAwMDAwMDEwNjggMDAwMDAgbg0KMDAwMDAwMTIyNCAwMDAwMCBuDQowMDAwMDAxNDEwIDAwMDAwIG4NCjAwMDAwMDE1ODkgMDAwMDAgbg0KMDAwMDAwMTc2OCAwMDAwMCBuDQowMDAwMDAyMTk3IDAwMDAwIG4NCjAwMDAwMDIzODMgMDAwMDAgbg0KMDAwMDAwMjc2OSAwMDAwMCBuDQowMDAwMDAzMTcyIDAwMDAwIG4NCjAwMDAwMDMzNTEgMDAwMDAgbg0KMDAwMDAwMDc2MCAwMDAwMCBuDQowMDAwMDAwODk3IDAwMDAwIG4NCnRyYWlsZXINPDwNL1NpemUgMTgNL0luZm8gMSAwIFIgDS9Sb290IDQgMCBSIA0vUHJldiAzNzIyIA0vSURbPGQ3MGY0NmM1YmE0ZmU4YmQ0OWE5ZGQwNTk5YjBiMTUxPjxkNzBmNDZjNWJhNGZlOGJkNDlhOWRkMDU5OWIwYjE1MT5dDT4+DXN0YXJ0eHJlZg0wDSUlRU9GDSAgICAgIA00IDAgb2JqDTw8IA0vVHlwZSAvQ2F0YWxvZyANL1BhZ2VzIDIgMCBSIA0vT3BlbkFjdGlvbiBbIDUgMCBSIC9YWVogbnVsbCBudWxsIG51bGwgXSANL1BhZ2VNb2RlIC9Vc2VOb25lIA0+PiANZW5kb2JqDTE2IDAgb2JqDTw8IC9TIDM2IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlIC9MZW5ndGggMTcgMCBSID4+IA1zdHJlYW0NCkiJYmBg4GVgYPrBAAScFxiwAQ4oLQDE3FDMwODHwKkyubctWLfmpsmimQ5AEYAAAwC3vwe0DWVuZHN0cmVhbQ1lbmRvYmoNMTcgMCBvYmoNNTMgDWVuZG9iag01IDAgb2JqDTw8IA0vVHlwZSAvUGFnZSANL1BhcmVudCAyIDAgUiANL1Jlc291cmNlcyA2IDAgUiANL0NvbnRlbnRzIDEwIDAgUiANL01lZGlhQm94IFsgMCAwIDYxMiA3OTIgXSANL0Nyb3BCb3ggWyAwIDAgNjEyIDc5MiBdIA0vUm90YXRlIDAgDT4+IA1lbmRvYmoNNiAwIG9iag08PCANL1Byb2NTZXQgWyAvUERGIC9UZXh0IF0gDS9Gb250IDw8IC9UVDIgOCAwIFIgL1RUNCAxMiAwIFIgL1RUNiAxMyAwIFIgPj4gDS9FeHRHU3RhdGUgPDwgL0dTMSAxNSAwIFIgPj4gDS9Db2xvclNwYWNlIDw8IC9DczUgOSAwIFIgPj4gDT4+IA1lbmRvYmoNNyAwIG9iag08PCANL1R5cGUgL0ZvbnREZXNjcmlwdG9yIA0vQXNjZW50IDg5MSANL0NhcEhlaWdodCAwIA0vRGVzY2VudCAtMjE2IA0vRmxhZ3MgMzQgDS9Gb250QkJveCBbIC01NjggLTMwNyAyMDI4IDEwMDcgXSANL0ZvbnROYW1lIC9UaW1lc05ld1JvbWFuIA0vSXRhbGljQW5nbGUgMCANL1N0ZW1WIDAgDT4+IA1lbmRvYmoNOCAwIG9iag08PCANL1R5cGUgL0ZvbnQgDS9TdWJ0eXBlIC9UcnVlVHlwZSANL0ZpcnN0Q2hhciAzMiANL0xhc3RDaGFyIDMyIA0vV2lkdGhzIFsgMjUwIF0gDS9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nIA0vQmFzZUZvbnQgL1RpbWVzTmV3Um9tYW4gDS9Gb250RGVzY3JpcHRvciA3IDAgUiANPj4gDWVuZG9iag05IDAgb2JqDVsgDS9DYWxSR0IgPDwgL1doaXRlUG9pbnQgWyAwLjk1MDUgMSAxLjA4OSBdIC9HYW1tYSBbIDIuMjIyMjEgMi4yMjIyMSAyLjIyMjIxIF0gDS9NYXRyaXggWyAwLjQxMjQgMC4yMTI2IDAuMDE5MyAwLjM1NzYgMC43MTUxOSAwLjExOTIgMC4xODA1IDAuMDcyMiAwLjk1MDUgXSA+PiANDV0NZW5kb2JqDTEwIDAgb2JqDTw8IC9MZW5ndGggMzU1IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+IA1zdHJlYW0NCkiJdJDBTsMwEETv/oo92ohuvXHsJEeggOCEwDfEIU1SCqIJIimIv2dthyJVQpGc0Xo88+xzL5beZ0DgN4IIq6oCzd8sK43amAyK3GKmTQV+J5YXo4VmjDYNYyOW1w8Ez6PQ4JuwfAkJyr+yXNgSSwt+NU+4Kp+rcg4uy9Q1a6MdarLcpgvUeUGh7RBFSLk1f1n+5FgsHJaZttFqA+tKLJhfZ3kEY+VcoHuUfvui2O3kCL9COSwk1Ok3deMEd6srUCVa2Q7Nftf1Ewar5a4nfxuu4v59NcLMGAKXlcjMLtwj1BsTQCITUSK52cC3IoNGDnto6l5VmEv4YAwjO8VWJ+s2DSeGttw/qmA/PZyLu3vY1p9p0MGZIs2iHdZxjwdNSkzedT0pJiW+CWl5H0O7uu2SB1JLn8rHlMkH2F+/xa20Rjp+nAQ39Ec8c1gz7KJ4T3H7uXnuwvSWl178CDAA/bGPlAplbmRzdHJlYW0NZW5kb2JqDTExIDAgb2JqDTw8IA0vVHlwZSAvRm9udERlc2NyaXB0b3IgDS9Bc2NlbnQgOTA1IA0vQ2FwSGVpZ2h0IDAgDS9EZXNjZW50IC0yMTEgDS9GbGFncyAzMiANL0ZvbnRCQm94IFsgLTYyOCAtMzc2IDIwMzQgMTA0OCBdIA0vRm9udE5hbWUgL0FyaWFsLEJvbGQgDS9JdGFsaWNBbmdsZSAwIA0vU3RlbVYgMTMzIA0+PiANZW5kb2JqDTEyIDAgb2JqDTw8IA0vVHlwZSAvRm9udCANL1N1YnR5cGUgL1RydWVUeXBlIA0vRmlyc3RDaGFyIDMyIA0vTGFzdENoYXIgMTE3IA0vV2lkdGhzIFsgMjc4IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMjc4IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgDTAgMCAwIDAgMCA3MjIgMCA2MTEgMCAwIDAgMCAwIDAgMCAwIDAgNjY3IDAgMCAwIDYxMSAwIDAgMCAwIDAgMCANMCAwIDAgMCAwIDAgNTU2IDAgNTU2IDYxMSA1NTYgMCAwIDYxMSAyNzggMCAwIDAgODg5IDYxMSA2MTEgMCAwIA0wIDU1NiAzMzMgNjExIF0gDS9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nIA0vQmFzZUZvbnQgL0FyaWFsLEJvbGQgDS9Gb250RGVzY3JpcHRvciAxMSAwIFIgDT4+IA1lbmRvYmoNMTMgMCBvYmoNPDwgDS9UeXBlIC9Gb250IA0vU3VidHlwZSAvVHJ1ZVR5cGUgDS9GaXJzdENoYXIgMzIgDS9MYXN0Q2hhciAxMjEgDS9XaWR0aHMgWyAyNzggMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDI3OCAwIDI3OCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCANMCAwIDAgNjY3IDAgMCAwIDAgMCAwIDAgMjc4IDAgMCAwIDAgMCAwIDAgMCA3MjIgMCAwIDAgMCAwIDAgMCAwIA0wIDAgMCAwIDAgMCA1NTYgNTU2IDUwMCA1NTYgNTU2IDI3OCAwIDU1NiAyMjIgMCAwIDIyMiA4MzMgNTU2IDU1NiANNTU2IDAgMzMzIDUwMCAyNzggNTU2IDUwMCAwIDAgNTAwIF0gDS9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nIA0vQmFzZUZvbnQgL0FyaWFsIA0vRm9udERlc2NyaXB0b3IgMTQgMCBSIA0+PiANZW5kb2JqDTE0IDAgb2JqDTw8IA0vVHlwZSAvRm9udERlc2NyaXB0b3IgDS9Bc2NlbnQgOTA1IA0vQ2FwSGVpZ2h0IDAgDS9EZXNjZW50IC0yMTEgDS9GbGFncyAzMiANL0ZvbnRCQm94IFsgLTY2NSAtMzI1IDIwMjggMTAzNyBdIA0vRm9udE5hbWUgL0FyaWFsIA0vSXRhbGljQW5nbGUgMCANL1N0ZW1WIDAgDT4+IA1lbmRvYmoNMTUgMCBvYmoNPDwgDS9UeXBlIC9FeHRHU3RhdGUgDS9TQSBmYWxzZSANL1NNIDAuMDIgDS9UUiAvSWRlbnRpdHkgDT4+IA1lbmRvYmoNMSAwIG9iag08PCANL1Byb2R1Y2VyIChBY3JvYmF0IERpc3RpbGxlciA0LjA1IGZvciBXaW5kb3dzKQ0vQ3JlYXRvciAoTWljcm9zb2Z0IFdvcmQgOS4wKQ0vTW9kRGF0ZSAoRDoyMDAxMDgyOTA5NTUwMS0wNycwMCcpDS9BdXRob3IgKEdlbmUgQnJ1bWJsYXkpDS9UaXRsZSAoVGhpcyBpcyBhIHRlc3QgUERGIGRvY3VtZW50KQ0vQ3JlYXRpb25EYXRlIChEOjIwMDEwODI5MDk1NDU3KQ0+PiANZW5kb2JqDTIgMCBvYmoNPDwgDS9UeXBlIC9QYWdlcyANL0tpZHMgWyA1IDAgUiBdIA0vQ291bnQgMSANPj4gDWVuZG9iag14cmVmDTAgMyANMDAwMDAwMDAwMCA2NTUzNSBmDQowMDAwMDAzNDI5IDAwMDAwIG4NCjAwMDAwMDM2NTggMDAwMDAgbg0KdHJhaWxlcg08PA0vU2l6ZSAzDS9JRFs8ZDcwZjQ2YzViYTRmZThiZDQ5YTlkZDA1OTliMGIxNTE+PGQ3MGY0NmM1YmE0ZmU4YmQ0OWE5ZGQwNTk5YjBiMTUxPl0NPj4Nc3RhcnR4cmVmDTE3Mw0lJUVPRg0=';
    }
    function getPdfDataPromise(httpService){
       var promise = loadData(httpService, 'https://file-examples-com.github.io/uploads/2017/02/file_example_CSV_5000.csv');
        return promise; 
    }

    function getCsvDataPromise(httpService){
        var promise = loadData(httpService, 'https://file-examples-com.github.io/uploads/2017/10/file-sample_150kB.pdf');
        return promise;
    }

    function loadData(httpService, url) {
        var config = { 
          'responseType': 'arraybuffer'    
          ,'Content Disposition' : 'attachment'     
        };
      
        var promise = httpService.get(url, config);
        return promise;
    }

    return {
        getCsvData: getCsvData,
        getCsvDataPromise: getCsvDataPromise,
        getPdfData: getPdfData,
        getPdfDataPromise: getPdfDataPromise
    };
};
var dataDummy = dataFilesDummyData();

function arrayBufeerHelperBase() {
    var factory = {};
     factory.arrayBufferToBase64 = function(buffer) {
        var binary = '';
        var bytes = new Uint8Array( buffer );
        var len = bytes.byteLength;
        for (var i = 0; i < len; i++) {
            binary += String.fromCharCode( bytes[ i ] );
        }
        return window.btoa( binary );
    }
    
    factory.base64ToArrayBuffer = function(base64) {
        var binary_string = window.atob(base64);
        var len = binary_string.length;
        var bytes = new Uint8Array(len);
        for (var i = 0; i < len; i++) {
            bytes[i] = binary_string.charCodeAt(i);
        }
        return bytes.buffer;
    }
    /*
    async function blobToBase64(blob){
        if (blob.arrayBuffer) {
            var buffer = await blob.arrayBuffer();
        }
        else {
            var buffer = await new Response(blob).arrayBuffer();  
        }
        var buffer = await new Response(blob).arrayBuffer();
        return arrayBufferToBase64(buffer);
    }
    */
    return factory;
}
var arrayBufferHelper = arrayBufeerHelperBase();

var app = angular.module('fileDownloaderModule', []);
app.controller('downloaderController', ['$timeout', '$element', '$window', downloaderController])
    .controller('dataController', ['$scope', '$http', '$timeout', dataController])
    .directive('fileDownloader', downloaderDirective);

function dataController($scope, $http) {
    var vm = this;
    
    $scope.loadCvsData = loadCvsData;
    $scope.loadPdfData = loadPdfData;

    $scope.$onInit =  function() {
        newWindow
    }
    //Method to be call by Angular fucntion type &. must be into $scope
    function loadCvsData() {
        var csvBase64Data = dataDummy.getCsvData();
        var arrayData = arrayBufferHelper.base64ToArrayBuffer(csvBase64Data);
        return arrayData;
    }
    
    //Method to be call by Angular fucntion type &. must be into $scope
    function loadPdfData() {
        var csvBase64Data = dataDummy.getPdfData();
        var arrayData = arrayBufferHelper.base64ToArrayBuffer(csvBase64Data);
        return arrayData;
    }
}

function downloaderDirective() {
    return {
        restrict: "E",        
        scope: {},
        bindToController: {
          data : '&',
          contentType: '@',
          filename: '@',
          caption : '@',
          buttonClass : '@',
          newWindow : '@'
        },
        templateUrl: "downloader/downloader.html",   
        controller: downloaderController,
        controllerAs: "downloaderCtrl"    
    }
};

function downloaderController($timeout, $element, $window) {
    var vm = this;
    vm.downloadFile = downloadFile;
    vm.$onInit =  function() {  
        vm.newWindow = vm.newWindow || false;
        vm.id = vm.id || Date.now();
    }    

    function downloadFile() {
        //debugger;
        if (!vm.filename || !vm.contentType || !vm.data) {
          return;
        }
        var objData = vm.data();
        var filename = vm.filename;
        var contentType= vm.contentType;
        //debugger;
        var dataTypeName = objData.constructor.name;
        switch(dataTypeName) {
            case 'Promise':
                objData.then(function(response) {    
                //debugger;    
                if(response.data) {
                    var data = response.data;
                } 
                else 
                {
                     var data = response;
                }
                switch(data.constructor.name) {
                    case 'Blob':
                    case 'ArrayBuffer':
                    //var base64 = _arrayBufferToBase64(data);
                    //var dataAgain = _base64ToArrayBuffer(base64);
                    console.log('Downloading...');
                    createDownloadFile(data, filename, contentType);
                    break;              
                }
                }, function() {
                   console.log('Error when download the file, data get issues');
                });
                break;
            case 'ArrayBuffer':
                console.log('Downloading...');
                createDownloadFile(objData, filename, contentType);          
                break;
            default:
                console.log('Data type '+ dataTypeName + ' of objData is unknown');
         }        
    }

    function createDownloadFile(fileData, filename, dataContentType) {
        //dataContentType = 'text/plan';
        var blob = new Blob([fileData], {'type': dataContentType});
        var _navigator = $window.navigator;
        var _userAgent = _navigator.userAgent;
        console.log(_userAgent);
        if (_navigator.msSaveOrOpenBlob) {
            //IE 11+
            _navigator.msSaveOrOpenBlob(blob, filename);
        } 
        else if (_userAgent.match("CriOS")) {
            //Chrome iOS
            var reader = new FileReader();
            reader.onloadend = function() {
                $window.open(reader.result);
            };
            reader.readAsDataURL(blob);
        } 
        else {
            //var newOpen = angular.bind($window, open, '', '_blank');
            
            //newOpen();
            //var normalOpen = $window.open;
            //normalOpen('', '_blank',  'rel=opener');

            var address = $window.URL.createObjectURL(blob);            
            
            /*
            if (_userAgent.match(/(ipad|iphone)/i)) {
                //iPad or iPhone
                //var newWindow = 
                debugger;
                console.log('Data begin set 0');
                $window.open(address + '&' +  filename, '_blank'); //'_blank'
                console.log('Data end set 0');
                //$timeout(function () {
                //    console.log('Data begin set 2');
                //    newWindow.location.href = address;
                //    console.log('Data end set 2');
                //}, 800);
            }
            else {
            */
                //Chrome, Edge, others
                var downloadLink = $element.find("a"); 
                if (!downloadLink[0]) {
                  downloadLink = angular.element('<a>');
                }            
                //debugger;
                downloadLink.attr("download", filename);
                downloadLink.attr("href", address);
                if (vm.newWindow) {
                    console.log('Opened in new window =' + vm.newWindow);
                    downloadLink.attr("target", '_blank');
                } else {
                    console.log('Opened in current window');
                }
                
                //downloadLink.attr("type", 'text/plan');
                //Attach to angular controller template html
                $element.append(downloadLink);            
                console.log(downloadLink[0]);
                downloadLink.ready(function() {
                    console.log('ready!!!');
                    console.log('anchor clicking...');                    
                    downloadLink[0].click();  
                    console.log('anchor clicked'); 
                    $timeout(function() {
                        console.log('detaching anchor...'); 
                        downloadLink.detach();
                        console.log('detached anchor'); 
                    }, 1000);
                });
            /*
            }
            */
        }
    }

    /*
    function createDownloadFile(data, filename, contentType){ 
        debugger;     
        var blob = new Blob([data], { 
          type: contentType      
        });    
        if (window.navigator.msSaveOrOpenBlob) {
            //IE 11+
            window.navigator.msSaveOrOpenBlob(blob, fileName);
        } 
        else
        if (navigator.userAgent.match("CriOS")) {
            //Chrome iOS
            var reader = new FileReader();
            reader.onloadend = function() {
                window.open(reader.result);
            };
            reader.readAsDataURL(blob);
        } 
        else {       
            var address = window.URL.createObjectURL(blob);
            var downloadLink = angular.element('<a>');        
        
            downloadLink.attr("href", address);
            angular.element(document.body).append(downloadLink);
        
            var userAgent = navigator.userAgent.toLowerCase();
            console.log(userAgent);
            debugger;
            if (userAgent.match(/(ipad|iphone)/)) {
                //Safari version 10.1+ has download attribute support
                if (userAgent.match(/version\/((?!10\.0)(\d\d(\.|\d)+)).+safari\/(\d(\.|\d)+)/)) {
                    downloadLink.attr("download", filename);
                    downloadLink.attr('target', '_parent');
                }          
                else {
                    downloadLink.attr('target', '_blank');
                }
            } 
            else {
                downloadLink.attr("download", filename);
            }
            debugger;
            //if (navigator.userAgent.toLowerCase().match(/(ipad|iphone)/)) {
            //    downloadLink.attr("target", "_blank");
            //} 
            console.log(downloadLink[0]);
            downloadLink.ready(function() {
                console.log('ready!!!');
                console.log('anchor clicking...');
                downloadLink[0].click();  
                console.log('anchor clicked'); 
            });
            $timeout(function() {
                console.log('detaching anchor...'); 
                downloadLink.detach();
                console.log('detached anchor'); 
                window.URL.revokeObjectURL(address);
            }, 1000);
        }
    }
    */
}
<style>
#dataTable_{{downloaderCtrl.id}} {
  font-family: Arial, Helvetica, sans-serif;
  border-collapse: collapse;
  width: 100%;
}
#dataTable_{{downloaderCtrl.id}} td, 
#dataTable_{{downloaderCtrl.id}} th {
  border: 1px solid #ddd;
  padding: 4px;
  width: 50%;
}
#dataTable_{{downloaderCtrl.id}} tr:nth-child(even){background-color: #f2f2f2;}
#dataTable_{{downloaderCtrl.id}} tr:hover {background-color: #ddd;}
#dataTable_{{downloaderCtrl.id}} th {
  padding-top: 2px;
  padding-bottom: 2px;
  text-align: left;
  background-color: #4CAF50;
  color: white;
}
</style>
<div style="font-size: 155%;">
<table id="dataTable_{{downloaderCtrl.id}}">
  <tr>
    <th style="width: 35%">Filename</th>
    <th style="width: 65%">Content Type</th>

  </tr>
  <tr>
    <td style="width: 35%">{{downloaderCtrl.filename}}</td>
    <td style="width: 65%">{{downloaderCtrl.contentType}}</td>    
  </tr>
  </table>
</div>
</br>
<button ng-click="downloaderCtrl.downloadFile()" class='{{downloaderCtrl.buttonClass}}'>
  <span>{{downloaderCtrl.caption}}</span>
</button>