0

I'm new to AngularJS and this is my first attempt in creating a custom directive. I found that the same piece of code for downloading a file was used in multiple places so I want to create a directive to improve modularity. Here's is my first attempt.

angular.module('defaultModule')
.directive('downloadFile', function () {
    return {
        restrict: 'A',
        
        scope: true,
        //scope: {
        //    fileURL: '@',
        //    fileName: '@',
        //},

        link: function (scope, element, attrs) {

            function startDownload() {
                console.log('scope.fileURL', 'scope.fileName'); // gives undefined values in isolated scope
                const link = document.createElement('a');
                link.setAttribute('target', '_blank');
                link.setAttribute('href', scope.fileURL);
                link.setAttribute('download', scope.fileName);
                document.body.appendChild(link);
                link.click();
                link.remove();
                console.log("download completed!");
            }

            element.on('click', startDownload);
        }
        
    };
});

and I use it like this in my html code

 <!-- {{fileURL}} and {{fileName}} are defined -->
 <button download-file type="button">Download</button>

I have a few questions regarding this implementation:

  • As you can see now, I'm currently using the inherited scope and it works fine, I tried to switch to isolated scope (which is commented out below the scope) because I heard it was the best practice. However, it seems that both fileURL and fileName have undefined values when I use the isolated scope. I do not know a proper way to call them in my link function.
  • For the link function, I've researched what element and attrs refer to, but most examples are for directives restricted to 'E'. If I want to use the directive as an attribute only, does element refer to the tag in which the directive is used, in that case what will attrs be?
  • In term of separation of concerns, is this link function well written? It solves the problem but it does try to manipulate the DOM instead of just setting it up. Would it be better if I use a controller instead?

Many thanks in advance!

  • 1. You can use isolated scope. I assume that you haven't passed fileURL an fileName correctly and because of this are undefined. If uppercase letters are used in parameters then you have use dash when passing values. Example: – AvgustinTomsic May 14 '21 at 17:54
  • 2. If directive is limited to A as attribute, then you will get in attrs all attributes that are used on HTML element where you use your directive. You can also try to log them out into console for example. – AvgustinTomsic May 14 '21 at 17:57
  • 3. I do not see any drawbacks using link function in your case. – AvgustinTomsic May 14 '21 at 18:00
  • @AvgustinTomsic for fileURL and fileName, these are not used as attributes, rather they are defined in the controller like $scope.fileURL = "someurl" and referenced in view as {{fileURL}}. – Francis.Tricka May 14 '21 at 18:57
  • But if you are using isolated scope then you have to pass them from parent scope to your directive as parameters using attributes. – AvgustinTomsic May 15 '21 at 10:37

0 Answers0