Триггер D3 перерисовать после окончания ng-repeat

У меня есть интересный вопрос относительно приложений, использующих AngularJS и D3. По сути, у меня есть ng-repeat, который повторяется в зависимости от содержимого массива. В этом массиве находятся объекты, которые содержат URL-адрес REST, к которому они периодически обращаются и получают данные. Как только они получают эти данные, график рисуется с использованием D3 (один график для каждого объекта в массиве).

У меня возникла проблема с динамическим добавлением объекта в этот массив с помощью пользовательского ввода и правильной работой чертежа. Похоже, что код d3 перепрыгивает через пушку и пытается выбрать элементы SVG, которые еще не были отрисованы, так как Angular все еще заканчивает добавлять материал в DOM с помощью ng-repeat.

Я попытался использовать $timeout, а также создал пользовательскую директиву, похожую на эту: ng-repeat finish event.

Это работает хорошо, но, похоже, вызывает событие только при первом запуске ng-repeat, а не когда я добавляю другой объект в массив. Есть какие-нибудь комментарии о том, как лучше всего справиться с этой ситуацией? Если бы я мог вызывать событие на основе $ last каждый раз, когда новый объект добавлялся / удалялся, а затем перебирал массив и вызывал функцию рисования, похоже, это сработало бы.

Ура!

Редактировать: код D3 в настоящее время похож на этот http://bl.ocks.org/mbostock/1346410 который представляет собой простое обновление кольцевой диаграммы с предупреждением о том, что перерисовка инициируется вызовом REST. Однако в будущем могут появиться более сложные графики, и именно поэтому я надеялся использовать D3.

Редактирование 2: я переместил весь свой код D3 в пользовательскую директиву, и после долгих раздумий он, кажется, работает почти так, как должен. Не изолируя область действия, пользовательский элемент имеет ту же область действия, что и ng-repeat, и может получить доступ к объекту и его свойствам, а также к соответствующим элементам DOM (в настоящее время я создаю DIV с идентификатором, уникальным для каждого объекта).).

Проблема теперь возникает при использовании d3.select... когда я пытаюсь выбрать DIV, в котором я хочу разместить чертеж, он не позволяет мне выбирать по идентификатору, так как он возвращает ноль... что очень странно в этом если я выберу все ("div"), он может найти нужный мне div, но не позволит мне выбрать только этот.

Вот JsFiddle, показывающий, что я имею в виду... проверьте консоль и увидите, что первый тест возвращает div "obj1", но второй выбор возвращает null.

Если бы я мог заставить это работать, а затем добавить свой холст SVG и рисовать в этом div, я думаю, что это сработало бы!

Соответствующий выбор:

    var test = d3.selectAll("div");
       console.log(test);
       var chart = d3.select("#obj" +obj.id);
       console.log(chart);

HTML, который должен создавать div:

    <div ng-repeat="object in myData">
        <div id="obj{{object.id}}">
            Hi 
           <bars-chart></bars-chart>
       </div>
   </div> 

http://jsfiddle.net/SleepyProgrammer/eN6p7/3/

1 ответ

Решение

Там нет необходимости использовать идентификатор для выбора вообще. Вы можете просто выбрать element[0] передано в угловую директиву link функция:

var chart = d3.select(element[0]).append('svg')

Например:

angular.module('myApp', []).
   directive('barsChart', function () {
     return {
         restrict: 'E',
         link: function (scope, element, attrs) {
             var chart = d3.select(element[0]).append('svg').attr({height: 20, width: 20});             
             chart.append('rect').attr({height: 10, width: 10});             
         } 
      };
   });

function Ctrl($scope, $timeout) {
    $scope.myData = [ {"id":"1"}, {"id":"2"}];

    // just to show that it reacts to changes in the data and will render more SVGs
    $timeout(function() {
        $scope.myData.push({"id":"3"});
    }, 3000);    
}

Смотрите JSFiddle здесь:

http://jsfiddle.net/4vdvq/2/

Другие вопросы по тегам