javascript - AngularJS 数据绑定(bind) - 观察周期未触发

标签 javascript angularjs d3.js nvd3.js

假设以下 JSFiddle:https://jsfiddle.net/pmgq00fm/1/

我希望我的 NVD3 图表能够根据第 39 行的 setInterval() 实时更新,该 setInterval() 会更新指令所绑定(bind)的数据。 以下是有关架构和代码的快速指南:

  • 该指令在 ThisController 的范围内
  • 使用指令中的“=”双向绑定(bind)数据
  • 只要指令在 $watch 周期内检测到数据发生变化,就应该在图表上调用更新函数。
  • $watch 是深度监视,因此应该检测值的变化
  • 指令中设置了一个时间间隔,以便在控制台中打印值的变化。每当调用 updateFnc 时, Controller 都会打印更新后的数组。
  • 由于某种原因我忽略了指令中数据的值从不与 Controller 中的数据匹配。
  • 这些值在 Controller 和指令中都会被修改。
  • 指令中的 $watch 仅在执行时调用
  • 代码基于this tutorial并遵守其中解释的数据绑定(bind)所需的所有步骤。

要进行调试,请运行 JSFiddle 并打开控制台以查看对象和调试打印。

HTML:

<div id="stats-container" ng-app="myApp" ng-controller="ThisController">
    <div id="nvd3-test" nvd3-discrete-bar data="data.graph">       
</div> 

JS:

myControllers.controller('ThisController', ['$scope', function ThisController($scope){
      $scope.data = { graph : [ ... ] };

      updateFnc = function(data){
        for(var i = 0; i < data[0].values.length ; i++){
          data[0].values[i].value = Math.random();
        }
        console.log(Date.now()/1000 + ": In Controller");
        console.log(data);
      };

      setInterval(function(){
        updateFnc($scope.data.graph);
      }, 1000);
 }]);

myServices.factory('NVD3Wrapper', ['NVD3S', 'D3S', '$q', '$rootScope', function NVD3Wrapper(nvd3s, d3s, $q, $rootScope){
  return {
    nvd3: nvd3s,
    d3: d3s,
    discreteBarChart : function(data, config){
        var $nvd3 = this.nvd3,
            $d3 = this.d3,
            $nvd3w = this, //In order to resolve the nvd3w in other scopes.
            d = $q.defer(); //Creating a promise because chart rendering is asynchronous
        $nvd3.addGraph(function() {
          ...
        });
        return {
          chart: function() { return d.promise; } //returns the chart once rendered.
        };
    },
    _onRenderEnd: function(d, chart){
      $rootScope.$apply(function() { d.resolve(chart); });
    },
  };
}]);

myDirectives.directive('nvd3DiscreteBar', ['NVD3Wrapper', function(nvd3w){
  return {
    restrict: 'EA',
    scope: {
      data: '=' // bi-directional data-binding
    },
    link: function(scope, element, attrs) {
      var chart,
          config = {
            target: element,
          };
      var wrapper = nvd3w.discreteBarChart(scope.data, config);
      wrapper.chart().then(function(chart){
        scope.$watch(function() { return scope.data; }, function(newValue, oldValue) {
          console.log(Date.now()/1000 + ": In Directive $watch");
          if (newValue)
              chart.update();
        }, true);
      });
      //For testing
      setInterval(function(){ console.log(Date.now()/1000 + ": In Directive"); console.log(scope.data); }, 1000);
    }
  };
}]);

任何帮助将不胜感激!多谢!

编辑:新的 JSFiddle 和 Andrew Shirley 的答案:https://jsfiddle.net/pmgq00fm/3/

最佳答案

添加行

$scope.$apply()

更新功能。这是因为,当在 javascript 中更新变量时,除了常见的 Angular 函数之外,Angular 并不知道更改,因此不会浪费任何精力来刷新 DOM。这会强制进行摘要循环,该循环应该会刷新您所看到的内容。

编辑:真正理解为什么你实际上使用了scope.apply是非常重要的,我觉得我没有很好地描述它。这是一篇比我的文章做得更好的文章。

http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

我指出这一点是因为你需要注意,如果你处于与 Angular 紧密相关的函数中(例如由 ng-click 调用的函数),那么如果你尝试使用作用域。$apply 你将得到 javascript错误,因为您已经处于摘要周期的中间。

关于javascript - AngularJS 数据绑定(bind) - 观察周期未触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33161007/

相关文章:

javascript - D3 顺序尺度和线性尺度之间的区别

javascript - 将 javascript 参数传递到 D3

javascript - 使用函数列表 knockout foreach

将对象推送到数组时出现 Javascript 意外标记点

javascript - 在 AngularJS 中异步加载数据的正确方法

javascript - 当我使用 ng-model 和 ng-change 时如何设置默认值来选择?

javascript - 使用 Protractor 检查 Angular ui 路由状态

javascript - 未捕获的语法错误 : Unexpected token var

javascript - Websocket 返回状态 200 而不是 101 (flask socket.io)

用于显示 "big-data"的 JavaScript 动态图形库?