AngularJS在ng-repeat之后添加jQuery dom eventlisteners

时间:2014-06-04 10:40:34

标签: javascript jquery angularjs d3.js

我正在将基于D3的网站迁移到有角度的图表。每个单独的图表仍将由D3绘制,但每个图表都将在角色directive上绘制图表。

其中一个图表元素由图表(SVG)和充当其图例的HTML表组成。

[ svg (chart) ][ table (legend) ]

D3绘制图表,我使用ng-repeat绘制图例。在这种情况下,图例和图表都需要是交互式的:需要有DOM事件监视器。然而,指令的控制器在 ng-repeat绘制图例之前运行(因此DOM元素尚不存在)。

视图:

<div ng-transclude></div>
<div class="wrapper">
    <svg></svg>
    <div class="valign">
        <table>
            <tr>
                <th>#</th>
                <th>Name</th>
                <th>BTC</th>
                <th>USD</th>
            </tr>
            <tr ng-repeat="item in items" class="legend item-{{item.title}}" title="{{item.title}}">
                <th>{{$index + 1}}</th>
                <td>{{item.title}}</td>
                <td>{{item.btc | bitcoin}}</td>
                <td>{{item.usd | currency}}</td>
            </tr>
        </table>
    </div>
</div>

指令:

angular
  .module('d3.charts', [])
  .directive('volumeElement', function() {
    return {
      restrict: 'E',
      scope: {
        data: '='
      },
      transclude: true,
      link: function(scope, element, attrs) {

        // todo: this needs to be changed upstream in the volume controller
        scope.mode = '24h';

        // the d3 chart function
        var chart = new window.WZB.VolumeChart(
          element.find('svg')[0],
          scope.data
        );

        var $paths, $legend;

        var render = function() {
          chart.mode = scope.mode;
          chart.render();

          $paths = element.find('.interactive');

          addHovers();
        }

        var addHovers = function() { 
          // PROBLEM: at this point the ng-repeat has not populated the legend yet
          $legend = element.find('.legend')
          $paths.hover(function(e) {
            var $path = $(e.target);
            var title = $path.attr('title');

            var legend = $legend
              .filter(function() {
                var nonActive = $(this).attr('title') !== title;

                if(!nonActive)
                  $(this).removeClass('blur')

                return nonActive;
              })

              $paths
                .not($path)
                .add(legend)
                .addClass('blur');
            }, function() {
              $paths.add($legend)
                .removeClass('blur');
            })
        }

        render();
      },
      templateUrl: '/volume-element.html'
    }
  })

我正在使用jQuery来获得更高级的DOM manips,我不仅可以依赖angular ng-mouseover指令,因为我需要角度生成表和D3生成SVG的事件监听器。

如果ng-repeat填充了图例,我该如何执行代码?


Hacky解决方案:

// todo: proper fix
// see @link https://stackoverflow.com/questions/24035289/angularjs-add-jquery-dom-eventlisteners-after-ng-repeat
setTimeout(addHovers, 0);

1 个答案:

答案 0 :(得分:0)

我重构了代码,我并没有以有棱角的方式思考。包含新指令,d3也创建表,而不是混合角度和d3用于相同的可视化。这样我就不再需要jQuery了。