在AngularJS绑定中的math函数
有没有办法在AngularJS绑定中使用math函数?
例如
<p>The percentage is {{Math.round(100*count/total)}}%</p>
这小提琴显示问题
http://jsfiddle.net/ricick/jtA99/1/
你必须注入Math
到你的范围,如果你需要使用它,因为$scope
对math一无所知。
最简单的方法,你可以做
$scope.Math = window.Math;
在你的控制器。 正确地做到这一点的angular度将创build一个math服务,我猜。
虽然接受的答案是正确的,你可以注入Math
使用angular度,对于这个特定的问题,更传统的/angular度的方式是数字filter:
<p>The percentage is {{(100*count/total)| number:0}}%</p>
您可以在这里阅读更多关于number
filter的信息: http : //docs.angularjs.org/api/ng/filter/number
我认为最好的方法是创build一个filter,如下所示:
myModule.filter('ceil', function() { return function(input) { return Math.ceil(input); }; });
那么标记看起来像这样:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
更新小提琴: http : //jsfiddle.net/BB4T4/
这是一个很好的答案,因为你没有给出你正在做的事情的完整背景。 被接受的答案将起作用,但在某些情况下会导致性能不佳。 那样的话,testing会更困难。
如果你这样做是静态表单的一部分,那很好。 即使不容易testing,被接受的答案也会起作用,而且这很容易。
如果你想成为这样的“angular”:
你会想保留任何“业务逻辑”(即改变数据显示的逻辑)。 这样你就可以对你的逻辑进行unit testing,所以你最终不会把你的控制器和你的视图紧密结合起来。 理论上,您应该能够将您的控制器指向另一个视图,并使用范围中的相同值。 (如果这是有道理的)。
您还需要考虑绑定内部的任何函数调用(如{{}}
或ng-bind
或ng-bind-html
)都必须在每个摘要上进行评估,因为angular度无法知道是否价值已经改变,或者不像在范围上的属性那样。
这样做的“angular度”方法是使用ng-change事件甚至$ watch来caching更改范围内属性的值。
例如用一个静态的forms:
angular.controller('MainCtrl', function($scope, $window) { $scope.count = 0; $scope.total = 1; $scope.updatePercentage = function () { $scope.percentage = $window.Math.round((100 * $scope.count) / $scope.total); }; });
<form name="calcForm"> <label>Count <input name="count" ng-model="count" ng-change="updatePercentage()" type="number" min="0" required/></label><br/> <label>Total <input name="total" ng-model="total" ng-change="updatePercentage()" type="number" min="1" required/></label><br/> <hr/> Percentage: {{percentage}} </form>
现在你可以testing它!
describe('Testing percentage controller', function() { var $scope = null; var ctrl = null; //you need to indicate your module in a test beforeEach(module('plunker')); beforeEach(inject(function($rootScope, $controller) { $scope = $rootScope.$new(); ctrl = $controller('MainCtrl', { $scope: $scope }); })); it('should calculate percentages properly', function() { $scope.count = 1; $scope.total = 1; $scope.updatePercentage(); expect($scope.percentage).toEqual(100); $scope.count = 1; $scope.total = 2; $scope.updatePercentage(); expect($scope.percentage).toEqual(50); $scope.count = 497; $scope.total = 10000; $scope.updatePercentage(); expect($scope.percentage).toEqual(5); //4.97% rounded up. $scope.count = 231; $scope.total = 10000; $scope.updatePercentage(); expect($scope.percentage).toEqual(2); //2.31% rounded down. }); });
更好的select是使用:
{{(100*score/questionCounter) || 0 | number:0}}
在未初始化的情况下,将公式的默认值设置为0。
假设您不需要在页面上进行批量计算,那么使用Angular进行简单math运算最简单的方法就是根据需要直接在单个绑定的HTML标记中。 这是一个例子:
{{(data.input/data.input2)| number}}
在这种情况下,你只需在()中做math运算,然后使用filter| 得到一个数字答案。 这里有更多关于格式化Angular数字的信息:
如果你想在Angular中做一个简单的循环,你可以很容易的在expression式中设置filter。 例如:
{{ val | number:0 }}
看到这个CodePen例子&其他数字filter选项。
有关使用数字filter的angular度文档
为什么不把整个mathobj包装在filter中?
var app = angular.module('fMathFilters',[]); function math() { return function(input,arg) { if(input) { return Math[arg](input); } return 0; } } return app.filter('math',[math]);
并使用:
{{number_var | math: '小区'}}
将全局math对象绑定到作用域上(记得使用$ window not window)
$scope.abs = $window.Math.abs;
在HTML中使用绑定:
<p>Distance from zero: {{abs(distance)}}</p>
或者为您所在的特定math函数创build一个filter:
module.filter('abs', ['$window', function($window) { return function(n) { return $window.Math.abs($window.parseInt(n)); }; });
在HTML中使用filter:
<p>Distance from zero: {{distance | abs}}</p>
这看起来不是一个非常有angular度的做法。 我不完全确定为什么它不起作用,但你可能需要访问范围才能使用这样的function。
我的build议是创build一个filter。 这是angular度的方式。
myModule.filter('ceil', function() { return function(input) { return Math.ceil(input); }; });
然后在你的HTML中这样做:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
这或多或less地是对三个答案的总结(SaraInésCalderón,klaxon和Gothburz),但是他们都增加了一些重要的东西,所以我认为值得join解决scheme并增加一些解释。
考虑你的例子,你可以在你的模板中进行计算:
{{ 100 * (count/total) }}
但是,这可能会导致很多小数位,所以使用filter是一个好方法:
{{ 100 * (count/total) | number }}
默认情况下,数字filter最多可以留下三个小数位 ,这就是fractionSize参数非常方便的地方( {{ 100 * (count/total) | number:fractionSize }}
),在你的情况下,
{{ 100 * (count/total) | number:0 }}
这也将结果四舍五入:
angular.module('numberFilterExample', []) .controller('ExampleController', ['$scope', function($scope) { $scope.val = 1234.56789; } ]);
<!doctype html> <html lang="en"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> </head> <body ng-app="numberFilterExample"> <table ng-controller="ExampleController"> <tr> <td>No formatting:</td> <td> <span>{{ val }}</span> </td> </tr> <tr> <td>3 Decimal places:</td> <td> <span>{{ val | number }}</span> (default) </td> </tr> <tr> <td>2 Decimal places:</td> <td><span>{{ val | number:2 }}</span></td> </tr> <tr> <td>No fractions: </td> <td><span>{{ val | number:0 }}</span> (rounded)</td> </tr> </table> </body> </html>
number
filter使用千位分隔符来格式化数字,所以它不是一个严格的math函数。
此外,它的小数“限制器”不会把任何一个小数点(如其他答案会让你相信),而是把它们round
。
所以对于你想要的任何math函数,你可以注入它(比注入整个Math对象更容易模拟),如下所示:
myModule.filter('ceil', function () { return Math.ceil; });
无需将其包装在另一个function中。