AngularJS+D3环形图数据异常与无限Digest循环报错求助
解决AngularJS + NVD3环形图的两类常见问题
我来帮你拆解这两个问题的根源,再给出对应的解决方案:
问题1:控制器写法导致环形图渲染失败(NaN错误)
原因分析
你的第一种写法里存在两个关键问题:
- 变量值传递的特性:
array在函数外部初始化时,y:one和y:two是把当时one、two的初始值(0)复制给了数组对象的y属性。JS的基本类型是值传递,不是引用传递,后续无论函数参数里的one、two怎么变,都不会自动更新array里的y值。 - 无效的变量重声明:函数里的
var one = one;完全多余,你只是重新声明了一个局部变量并赋值为参数本身,根本没有修改外部array的内容。最终返回的array里的y始终是0,NVD3在计算环形图的位置、角度时,会因为数值异常(比如分母为0)导致NaN,进而抛出translate(NaN,NaN)的错误。
临时修复(仅解决渲染,还需处理循环问题)
如果要保留类似结构,需要在函数内部主动更新数组对象的y值:
var array = [{ key:"Discounted", y:0}, {key: "NotDiscounted", y: 0 }]; $scope.donatdata = function(one, two) { // 直接更新数组里的对象属性,而非返回新数组 array[0].y = one; array[1].y = two; return array; };
问题2:返回新数组导致无限Digest循环($rootScope/infdig)
原因分析
AngularJS的Digest循环会监控绑定数据的变化,每次执行时都会调用donatdata(30,20)获取数据。你的第二种写法每次调用都会返回一个全新的数组对象(即使内容完全一致),Angular会判定数据发生了变化,于是再次触发Digest循环,反复执行直到超过最大循环次数(默认10次),最终抛出$rootScope/infdig错误。
最终解决方案:复用固定数组实例,仅更新内部属性
正确的做法是在控制器里维护一个固定的数组实例,只更新内部的y属性值,而不是每次都返回新数组。这样Angular检测到的是数组内部属性的变化,而非数组对象本身的替换,就不会触发无限循环。
完整控制器写法
// 初始化固定的数组实例 $scope.donutData = [ { key: "Discounted", y: 0 }, { key: "NotDiscounted", y: 0 } ]; // 提供更新数据的方法,而非直接返回新数组 $scope.updateDonutData = function(one, two) { $scope.donutData[0].y = one; $scope.donutData[1].y = two; }; // 初始化数据(可根据需求调整) $scope.updateDonutData(30, 20);
模板写法
<!-- 直接绑定到固定的数组实例,无需调用函数返回新数组 --> <nvd3 options="donutoptions" data="donutData"></nvd3>
动态更新场景示例
如果需要在用户操作或其他事件中更新环形图数据,直接调用updateDonutData方法即可:
// 比如按钮点击事件触发更新 $scope.onDataUpdate = function() { $scope.updateDonutData(50, 50); };
补充:为什么第一种写法里one和two的值无法更新?
因为你在函数外部初始化array时,y:one是把当时one的数值(0)赋给了对象的y属性,而非引用变量one本身。JS中基本类型(数字、字符串等)是按值传递的,后续修改one或者函数参数里的one,都不会影响已经赋值给y的数值。再加上你的函数里根本没有对array的内容做任何修改,所以返回的始终是初始状态的数组。
内容的提问来源于stack exchange,提问作者user6496229
相关产品推荐
相关产品推荐

