Search code examples
angularjsencapsulation

Angular: How to encapsulate logic in a directive?


I wonder how I can encapsulate functionality inside of an angular directive according to Rober C. Martin's "Clean Code" book. I want to omit comments and use functions with speaking names instead.

Imagine this code:

app.directive('myDirective' function() {

return  {
    link: function(scope) {

        // initialize visual user state
        scope.visualUserState = { 
             // some very detailed state initialization 
        } 
    }
})

To encapsulate the load functionality, I would like to replace this code like this:

app.directive('myDirective' function() {

return  {
    link: function(scope) {

        scope.initializeVisualUserState = function() {
            scope.visualUserState = { 
               // some very detailed state initialization 
            }
        }


        scope.initializeVisualUserState();

    }
})

What I do not like on the second approach is that "loadDataFromServer" is some functionality that is only used by the link function and not by the view, so I violate the rule that scope should only hold data and functions that is used to interact with the view.

Also the code is not very readable I think.

As the functionality handles very private stuff of the directive, I think that using and injecting a service is not the right way to go.

What would be a better practice to encapsulate this functionality?


Solution

  • You should use a controller to add logic to your directive. In your controller you can inject Services. It's best to write a service for a single purpose, and simply let your controller call the services.

    In fact you should only use the link function if you need to have your DOM-node, which is actually pretty close to never.

    Read the styleguide by John Papa

    angular.module('myModule', []);
    
    // Controller
    (function() {
      angular
        .controller('myModule')
        .controller('MyController', ['$scope', 'DataService', function($scope, DataService) {
          DataService
            .retrieveData()
            .then(function(data) {
              $scope.visualUserState = data;
            });
        }]);
    })();
    
    // Directive
    (function() {
      angular
        .module('myModule')
        .directive('myDirective', function() {
          return {
            'restrict': 'E',
            'scope': true,
            'controller': 'MyController',
            'controllerAs': '$ctrl'
          };
        });
    })();