I am attempting to loop through an array and create multiple instances of a custom directive that creates different graphs based on some variables on the rootScope. Everything works fine except when I try to place those in a view and call ng-init to a method on the scope and pass it arguments.
What I am finding is that ng-init seems to run before anything (and I think ng-init is the wrong approach), which causes errors because the variables being set in the method aren't set yet when the ng-init runs in the view.
When I first load the index view, then go into this view, all is well, but when I try to load this view first or reload it, I am getting the errors. The ng-init is trying to call the chart() method before anything else runs.
On the index view, I have this chart in a modal that gets called onclick, so ng-init is not needed, therefore it works great.
I am a little stuck and what I need is advice on the right or better way to accomplish this.
On the detail view, I need to loop across that array to get four charts based on four different objects of data.
The data is a static file for now, as this is a prototype.
My code is essentially this:
View:
<div id=chart_list>
<div class=chart ng-repeat=val in ['abc', 'def', 'ghi', 'jkl'] ng-init=chart('line', val, itemId, val)>
<h3>{{val | uppercase}}</h3>
<chart/>
</div>
</div>
AppController method:
// get data set up for chart consumption
$scope.chart = function(chart, kpi, socId, chartId) {
$rootScope.visualize = {};
$rootScope.visualize.chart = chart;
$rootScope.visualize.chartId = chartId;
$rootScope.visualize.val = val;
$rootScope.visualize.item = $rootScope.itemList[itemId];
$rootScope.visualize.valName = $rootScope.visualize.item[val].name;
};
DetailView controller:
app.controller('ItemDetailController', function($scope, $rootScope, $routeParams, ItemList) {
var itemId = $scope.itemId = $routeParams.itemId;
ItemList.get({}, function(res) {
$rootScope.itemList = res.data;
$scope.item = $rootScope.itemList[itemId];
});
});
Service:
app.factory('ItemList', function($resource){
return $resource(/api/item-list.json);
});
Directive:
app.directive('chart', function() {
return {
restrict: 'E',
link: function(scope, element, attrs){
if ($(window).width() <= 1200){
var width = 300;
} else {
var width = 450;
}
var visualize = scope.visualize;
var data = visualize.soc[visualize.val].data;
var numTicks = Object.keys(data).length;
element.append('<div class=chart_container><div id=y_axis' + visualize.chartId +' class=y_axis></div><div id=chart' + visualize.chartId + ' class=chart></div><div id=x_axis' + visualize.chartId + ' class=x_axis></div></div>');
element.append('<div id=legend_container' + visualize.chartId +' class=legend_container><div id=smoother' + visualize.chartId +' title=Smoothing></div><div id=legend' + visualize.chartId +'></div></div>');
var valSeries = [];
var valSeries2 = [];
var valSeries3 = [];
var valMap = {};
var i = 0;
Object.keys(data).forEach(function(propertyName) {
var value = data[propertyName];
var val2 = (Math.random() * (102 - 87) + 86) / 100;
var val3 = (Math.random() * (95 - 70) + 69) / 100;
valSeries.push({x: i, y: data[propertyName].amount});
valSeries2.push({x: i, y: data[propertyName].amount * val2});
valSeries3.push({x: i, y: data[propertyName].amount * val3});
valMap[i] = data[propertyName].name;
i++;
});
var graph = new Rickshaw.Graph({
element: document.querySelector('#chart' + visualize.chartId),
width: width,
height: 150,
renderer: visualize.chart,
stroke: true,
series: [
{
data: valSeries3,
color: '#F0AD4E',
name: 'Three years ago',
},
{
data: valSeries2,
color: '#5BC0DE',
name: 'Two years ago',
},
{
data: valSeries,
color: '#5CB85C',
name: 'Past year'
}
]
});
var format = function(n) {
var map = valMap;
return map[n];
}
var x_ticks = new Rickshaw.Graph.Axis.X({
graph: graph,
width: width,
orientation: 'bottom',
element: document.getElementById('x_axis' + visualize.chartId),
pixelsPerTick: width/numTicks,
tickFormat: format
});
var y_axis = new Rickshaw.Graph.Axis.Y({
graph: graph,
orientation: 'left',
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
element: document.getElementById('y_axis' + visualize.chartId),
});
graph.render();
var hoverDetail = new Rickshaw.Graph.HoverDetail({
graph: graph,
formatter: function(series, x, y) {
var content = app.lib[visualize.dataFormat](parseInt(y)) + <br>;
return content;
}
});
var legend = new Rickshaw.Graph.Legend( {
graph: graph,
element: document.getElementById('legend' + visualize.chartId)
} );
var shelving = new Rickshaw.Graph.Behavior.Series.Toggle( {
graph: graph,
legend: legend
} );
}
};
});
Edit:
I fixed this by removing the chart method altogether and replacing ng-init with attributes. Something like this:
<chart data-attrone=somedata data-attrtwo=some other data />
Then the attrs are available in the directive with attrs.attrone
, etc.
Attribute names must be lower-case.
Hope this helps someone in the future.