2014-11-04 4 views
3

Я пытаюсь написать директиву для рисования штрих-карт, и я хотел бы, чтобы он перерисовывал диаграмму каждый раз, когда данные меняются. Сейчас у меня это:

/* This directive will create a bar chart based on a dataTable. 
* It expects the first column of the data table to contain the labels. 
* If more than 2 columns (labels plus more than one value) are supplied, 
* all bars generated by values in one row will be grouped together, making 
* an easy visual comparison (benchmark). 
* If the option overlay is supplied, the odd value columns will be drawn 
* underneath the even values (Ex [label, col1, col2, col3, col4], with overlay = true will result 
* in col1 and col3 to be drawn underneath col2 and col4 
*/ 


angular.module('kapstok').directive('nBarChart', ['$window', '$location', '$parse', '$timeout', 
    function($window, $location, $parse, $timeout){ 
    return{ 
    restrict: 'E', 
    scope: true, 
    link: function(scope, elm, attrs){ 

     // Read all the different parameters givin in the directive declaration. 
     // If options are not given, they are replaced by their default values. 
     var dataGetter  = $parse(attrs.data); 
     var data = dataGetter(scope) || undefined; 
     if(!data){ 
     throw Error("No (valid) data source specified!"); 
     } 



      // Redraw the table once the table gets updated. However, usually multiple elements 
     // of the table will be updated at the same time, while the watch will get triggered 
     // at each update. To prevent this, we give it a timeout of half a second, 
     // allowing all the updates to be applied before the table is redrawn. 
     scope.$watch(function(){ return data.getVersion(); }, $timeout(drawChart, 500)); 

Затем в моем контроллере я:

controlmodule.controller('PrefscanController',['$http', '$scope', 'DataTable', function($http, $scope, DataTable){ 
    $scope.myData = new DataTable(); 
    $scope.myData.addColumn("string", "label"); 
    $scope.myData.addColumn("number", "survey"); 
    $scope.myData.addColumn("number", "benchmark"); 
    $scope.myData.addColumn("number", "break-it"); 

    $scope.myData.addRow(['test', 20, 10, 4]); 
    $scope.myData.addRow(['test2', 42, 13, 2]); 


    $scope.hideBenchmark = function(){ 
    console.log("myData.version = ", $scope.myData.getVersion()); 
    $scope.myData.hideColumn(2); 
    console.log("myData.version = ", $scope.myData.getVersion()); 
    } 

Во всех функциях из DataTable, когда что-то меняется свойством, называемое «версией» увеличивается, что и Я хочу смотреть $ watch.

В моем шаблоне у меня есть кнопка с ng-кликом, которая вызывает функцию hideBenchmark. Эта функция вызывается, обновляется версия dataTable, но, что бы я ни старался, часы не срабатывают.

Я попытался использовать $ scope. $ Appy()/$ scope. $ Digest() в моей функции hideBenchmark, попробовал добавить «true» к часам (искал объектное неравенство), попытался посмотреть 'attrs.data ',' data.version ', и никто из них, похоже, не запускает часы! Я знаю, что могу создать другую переменную в области, независимой от этих данных, и следить за ней и изменять ее каждый раз, когда я меняю данные, но это кажется уродливым и ненужным.

Кто-нибудь знает, ПОЧЕМУ часы не срабатывают, и как я могу заставить его делать то, что я хочу?

С уважением,

Линус

+0

Вы пытались помещать «данные» в область действия своей директивы, вместо того чтобы получать ее из атрибутов? –

ответ

2

По предложению Сунил, вы должны поместить его в рамки:

scope: { 
    data: '=' 
} 

Потому что, если вы не сделаете это, то данные не обновляется в пределах директивы.

Здесь скрипкой: http://jsfiddle.net/0t4z02yw/2/

+0

Спасибо вам большое! Это сделал трюк! – Linus

0

вы передаете вызов функции в $ часов, она должна быть ссылка или заявление, я думаю.

scope.$watch(function(){ 
     return data.getVersion(); 
    }, function(){ 
     $timeout(drawChart, 500) 
    }); 

Очевидно, drawChart должен быть определен в этом контексте для этой работы ... то, что вы можете попробовать, чтобы увидеть, если $ наблюдающий в настоящее время запускается регистрирует значение версии.

scope.$watch(function(){ 
     return data.getVersion(); 
    }, function(v){ 
     console.log(v) 
    }); 

Примечание: для всех остальных ответов, которые необходимо добавить в область видимости, это ложь. Вам не нужно это делать, потому что вы передаете свою собственную функцию функции $ watcher. То, как вы получаете свой элемент данных, прекрасно, с услугой $parse.

0

причина, по которой она в настоящее время не работает, потому что ничто не делает внешний объем (контроллер) уведомляющим внутреннюю область (директиву), которую он должен переваривать, - это что-то изменилось. Это происходит потому, что объект данных не является частью области действия директивы. Пара способов борьбы с ним:
Во-первых, вы можете передать объект данных в директиве и создать изолированную сферу:

scope: {data: '='} 

Или вы можете передать указатель на функцию, чтобы получать уведомления, когда данные изменения (hideBenchmark) в вашем случае:

scope: {hideBenchmark: '@'} 

Here является plunker для первого метода.

Смежные вопросы