-3

Is it considered good practice to have:

  1. Single, general directive that has multiple data-* parameters and serial data is binded from controller
  2. Single, general directive that has config and serial data is from controller
  3. Multiple directives that has some pre-defined config inside directive, some of config is by data-* parameters and serial data is binded from controller

For example, I have a template were I need to create ~16 charts (Highcharts/amCharts). All of them won't have the same configuration and serial data.

Example of 1 option:

angular.module('myApp')
  .directive('ngHighcharts', () => ({
    restrict: 'AE',
    replace: 'true',
    scope: {
      data: '='
    },
    template: '<div></div>',
    link: function(scope, $elem, $attrs) {

      var chart, config;
      config = {
        chart: {
          renderTo: $elem[0],
          type: $attrs.type ? $attrs.type : 'bar'
        },
        exporting: {
          enabled: $attrs.exporting ? $attrs.exporting : false
        },
        title: {
          text: $attrs.title ? $attrs.title : ''
        },
        xAxis: {
          categories: $attrs.categories ? $attrs.categories : data[0]
        },
        tooltip: {
          valueSuffix: $attrs.valueSuffix ? $attrs.valueSuffix : ''
        },
        plotOptions: {
          bar: {
            dataLabels: {
              enabled: $attrs.dataLabels ? $attrs.dataLabels : false
            }
          }
        },
        series: scope.data
      };

      chart = new Highcharts.Chart(config);

      scope.$on('$destroy', function () {
        scope.$evalAsync(function () {
          chart.destroy ();
        });
      });

    }
   }));

Example of 2 option:

angular.module('myApp')
  .directive('ngHighcharts', () => ({
    restrict: 'AE',
    replace: 'true',
    scope: {
      config: '=',
      data: '='
    },
    template: '<div></div>',
    link: function(scope, $elem, $attrs) {

      config.chart.renderTo = $elem[0];
      var chart = new Highcharts.Chart(config);

      scope.$on('$destroy', function () {
        scope.$evalAsync(function () {
          chart.destroy ();
        });
      });

    }
   }));

Example of 3 option:

angular.module('myApp')
  .directive('ngHighcharts', () => ({
    restrict: 'AE',
    replace: 'true',
    scope: {
      data: '='
    },
    template: '<div></div>',
    link: function(scope, $elem, $attrs) {

      var chart, config;
      config = {
        chart: {
          renderTo: $elem[0],
          type: 'bar'
        },
        exporting: {
          enabled: true
        },
        title: {
          text: $attrs.title ? $attrs.title : ''
        },
        xAxis: {
          categories: $attrs.categories ? $attrs.categories : data[0]
        },
        tooltip: {
          valueSuffix: $attrs.valueSuffix ? $attrs.valueSuffix : ''
        },
        plotOptions: {
          bar: {
            dataLabels: {
              enabled: true
            }
          }
        },
        series: scope.data
      };

      chart = new Highcharts.Chart(config);

      scope.$on('$destroy', function () {
        scope.$evalAsync(function () {
          chart.destroy ();
        });
      });

    }
   }));

What would be considered best practice in this situation?

1

It really depends on the use case. You describe a chart directive. At first glance, its configuration appears fairly static. That is, you can configure it per view and not give it a second thought. In that case, attribute-based configuration is nice. Coupled with some sensible defaults, it greatly reduces the moving parts from outside your directive.

The thing is, life is rarely that simple (or fair). Imagine that your boss shows up an hour before end-of-work on Friday. She's just come from a meeting of project shareholders and was blindsided by their assumption that salespeople could configure reports (including charts) as they saw fit. This makes your attribute-based configuration not only wrong, but less straightforward to "fix". (I won't call it a true fix since it's a new requirement.) If configuration had always been data, it would be conceptually simple to change the data source. (Never mind there are new UIs to build and now you're going to miss Happy Hour at The Stumble Inn.)

So, it's a tradeoff like everything else. It's flexibility versus simplicity. Flexibility is always cool, but its cost is complexity. You have to decide what you value. You can't get something for free. Remember TANSTAAFL.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.