Abhirath Mahipal Abhirath Mahipal - 3 months ago 22
JSON Question

Optimal way to use Angular Directives and JSON

I want an efficient way to factor an Angular Directive that is written to display a chart.

After reading other answers here, I found a nice way to create a directive that displays a single chart without any problem.

How do I reuse the same directive to display different charts? Each chart needs a JSON object that has settings and data in order to render.

I don't want to pollute my Angular View by typing 100-150 lines of JSON and passing it in via the directive.

Details:-


  • Each chart has some common key/value pairs that I can leave in the directive.

  • How do I infuse chart specific key & value pairs in each directive?



Eg:- Say I want one chart to have green bars and the other chart to have red lines.

Angular Directive

(function () {

'use strict';

angular
.module("analytics")
.directive("angularDirectiveAmcharts", angularDirectiveAmcharts);

function angularDirectiveAmcharts() {

var directive = {
link: link,
restrict: 'A',
replace: true,
scope: {
chartdata: '=',
type: '=',
customstyle: '@',
chartsettings: '=',
chartid: '@'
},
template: '<div id="{{ chartid }}" style="{{ customstyle }}"></div>'
};

return directive;


function link(scope, elem, attrs) {
AmCharts.makeChart(scope.chartid, {
"type": "serial",
"categoryField": "date",
"autoMarginOffset": 10,
"marginRight": 20,
"marginTop": 20,

//I've deleted lots of keys and values for the sake of brevity


"dataProvider": scope.chartdata
});


}
}
})();


View

<div class="chartarea" ng-controller="pcController as vm">

<div angular-directive-amcharts chartid="chartdiv" chartdata="vm.chart_data"></div>

</div>


I am particular about maintainability because a lot of changes are going to made after I'm done with my internship.

Answer

Parts of the given code in this answer are based on another answer

You could use a service to provide a standard configuration to all of your chart directives. In this service you can define this standard configuration once and merge it with a specific configuration each time, a directive is created. This way you only have to declare minor changes in your controller.

Nonrequired but possible config binding into directive:

<div ng-controller="myCtrl">
    <my-chart></my-chart>
    <my-chart config="conf"></my-chart>
</div>

Specific configuration in controller:

myapp.controller('myCtrl', function ($scope) {
    $scope.conf = {
        graphs: [{ type: 'column' }]
    };
});

Service for default configuration (using jQuerys way to deep merge objects):

myapp.service('chartService', function () {
    this.defaultConfig = {
        "type": "serial",
        // reduced object for readabilty
    };
    this.getConfig = function (mergeObj) {
        return $.extend(true, {}, this.defaultConfig, mergeObj);
    }
});

The data is get through another service, and added to the configuration after the merge:

var config = chartService.getConfig(scope.config || {});
config.dataProvider = dataProvider.getData();
chart = AmCharts.makeChart(element[0], config);

I've prepared a fiddle, so you can take a look into an example.