9

I got help to save json as file in client side here. Code is very short as in this fiddle.

var a = document.createElement('a');
a.download    = "backup.json";
a.href        = url;
a.textContent = "Download backup.json";

document.getElementById('content').appendChild(a);

I was trying to create an angularjs directive so that it calls a method in scope to get the data. Along this line.

module.directive('myDownload', function ($compile) {
    return {
        restrict:'E',
        scope:{ getData:'&getData'},
        link:function (scope, elm, attrs) {
            elm.append($compile(
                '<a class="btn" download="backup.json"' +
                    'href=' + scope.getData() + '>' +
                    'Download' +
                    '</a>'
            )(scope));
        }
    };
});

This doesn't work. How can make the linked fiddle into a directive?

Community
  • 1
  • 1
bsr
  • 57,282
  • 86
  • 216
  • 316

2 Answers2

14

How about something like this: Fiddle

Here's the directive code:

module.directive('myDownload', function ($compile) {
  return {
    restrict:'E',
    scope:{ getUrlData:'&getData'},
    link:function (scope, elm, attrs) {
        var url = URL.createObjectURL(scope.getUrlData());
        elm.append($compile(
            '<a class="btn" download="backup.json"' +
                'href="' + url + '">' +
                'Download' +
                '</a>'
        )(scope));
     }
  };
});

Controller:

module.controller('MyCtrl', function ($scope){
  var data = {a:1, b:2, c:3};
  var json = JSON.stringify(data);

  $scope.getBlob = function(){
    return new Blob([json], {type: "application/json"});
  }
});
nowk
  • 32,822
  • 2
  • 35
  • 40
mfelix
  • 1,834
  • 17
  • 18
  • 1
    well, one small issue though. Is it possible to fetch new data whenever I click the link. I noticed getBlob() only calls once, initially. Is it possible? – bsr May 02 '13 at 17:53
  • In that case I would start by binding the directive's scope to whichever data in your controller's scope can change the data that would be given by clicking the link. Then I would try using scope.$watch on those bound properties inside the directive's link function to make it regenerate the download link anytime any of them changes. That's what comes to mind, but maybe there's a better way. – mfelix May 02 '13 at 18:39
  • thanks you for all the effort.My intention was not to retrieve the data till it necessary. When I think about it, it may better to show another scree/preview using normal action, then use that data to do download url. Thanks again for your effort. Cheers. – bsr May 02 '13 at 19:33
  • What if the blob type differs? – Rafael Jun 16 '16 at 11:28
2

I ended up here trying to solve a similar issue. in my Angular page, I have a JSON retrieved via Ajax that is rendered as HTML, but I wanted the "raw" JSON to be downloadable via a link.

the issue with the OP's and most-voted approach is that the HTML DOM is manipulated within your controller, which kind of defeats the purpose of using MVVM. i think the reason you're doing all of that is because Angular blocks creation of links for blobs (by pre-pending 'unsafe:' to the resulting blob URL).

Fortunately, Angular provides a way to apply a whitelist certain URL prefixes so it will not be blocked when you use URL.createObjectURL()...in this case, we include blob

here is my take on it running on JSFiddle

Community
  • 1
  • 1
Dexter Legaspi
  • 3,192
  • 1
  • 35
  • 26