title: AngularJS element directive with ng-init runs before view renders
body: <p>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. </p>
  
  <p>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. </p>
  
  <p>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. </p>
  
  <p>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. </p>
  
  <p>I am a little stuck and what I need is advice on the "right" or better way to accomplish this. </p>
  
  <p>On the detail view, I need to loop across that array to get four charts based on four different objects of data. </p>
  
  <p>The data is a static file for now, as this is a prototype. </p>
  
  <p>My code is essentially this: 
  View: </p>
  
  <pre><code>&lt;div id="chart_list"&gt;
    &lt;div class="chart" ng-repeat="val in ['abc', 'def', 'ghi', 'jkl']" ng-init="chart('line', val, itemId, val)"&gt;
      &lt;h3&gt;{{val | uppercase}}&lt;/h3&gt;
      &lt;chart/&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>AppController method: </p>
  
  <pre><code>// 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;
  </code></pre>
  
  <p>};</p>
  
  <p>DetailView controller: </p>
  
  <pre><code>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];
    });
  
  
  });
  </code></pre>
  
  <p>Service:</p>
  
  <pre><code>app.factory('ItemList', function($resource){
    return $resource("/api/item-list.json");
  });
  </code></pre>
  
  <p>Directive:</p>
  
  <pre><code>app.directive('chart', function() {
    return {
      restrict: 'E',
      link: function(scope, element, attrs){
  
        if ($(window).width() &lt;= 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('&lt;div class="chart_container"&gt;&lt;div id="y_axis' + visualize.chartId +'" class="y_axis"&gt;&lt;/div&gt;&lt;div id="chart' + visualize.chartId + '" class="chart"&gt;&lt;/div&gt;&lt;div id="x_axis' + visualize.chartId + '" class="x_axis"&gt;&lt;/div&gt;&lt;/div&gt;');
        element.append('&lt;div id="legend_container' + visualize.chartId +'" class="legend_container"&gt;&lt;div id="smoother' + visualize.chartId +'" title="Smoothing"&gt;&lt;/div&gt;&lt;div id="legend' + visualize.chartId +'"&gt;&lt;/div&gt;&lt;/div&gt;');
  
        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)) + "&lt;br&gt;";
            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
        } );
  
      }
    };
  });
  </code></pre>
  
  <p><strong>Edit:</strong><br>
  I fixed this by removing the chart method altogether and replacing ng-init with attributes. Something like this:</p>
  
  <pre><code>&lt;chart data-attrone="somedata" data-attrtwo="some other data" /&gt;
  </code></pre>
  
  <p>Then the attrs are available in the directive with <code>attrs.attrone</code>, etc. </p>
  
  <p>Attribute names must be lower-case.</p>
  
  <p>Hope this helps someone in the future. </p>