有没有办法在AngularJS绑定中使用数学函数?
e.g。
<p>The percentage is {{Math.round(100*count/total)}}%</p>
这个小提琴显示了问题
答案 0 :(得分:321)
如果您需要使用它,则必须将Math
注入您的范围
$scope
对数学一无所知。
最简单的方法,你可以做到
$scope.Math = window.Math;
在您的控制器中。 正确地执行此操作的Angular方法是创建Math服务,我想。
答案 1 :(得分:300)
虽然接受的答案是正确的,你可以注入Math
以角度使用它,对于这个特殊的问题,更常规/角度的方式是数字过滤器:
<p>The percentage is {{(100*count/total)| number:0}}%</p>
您可以在此处详细了解number
过滤器:http://docs.angularjs.org/api/ng/filter/number
答案 2 :(得分:61)
我认为最好的方法是创建一个过滤器,如下所示:
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
然后标记看起来像这样:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
更新了小提琴:http://jsfiddle.net/BB4T4/
答案 3 :(得分:37)
这是一个毛茸茸的回答,因为你没有给出你正在做的事情的完整背景。接受的答案是有效的,但在某些情况下会导致性能不佳。那,并且它将更难测试。
如果您将此作为静态表单的一部分,那很好。接受的答案将起作用,即使它不容易测试,也很容易。
您需要保留任何“业务逻辑”(即改变要显示的数据的逻辑)。这样您就可以对逻辑进行单元测试,因此您最终不会将控制器与视图紧密耦合。从理论上讲,您应该能够将控制器指向另一个视图并使用范围中的相同值。 (如果这是有道理的)。
您还需要考虑在每个摘要中必须评估绑定内部的任何函数调用(例如{{}}
或ng-bind
或ng-bind-html
) ,因为angular无法知道值是否已更改,或者与范围内的属性一样。
执行此操作的“有角度”方法是使用ng-change事件甚至是$ watch将值更改为更改范围内的属性。
例如,使用静态表单:
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>
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.
});
});
答案 4 :(得分:8)
更好的选择是使用:
natural join
在未初始化值的情况下,将方程的默认值设置为0.
答案 5 :(得分:8)
为什么不将整个数学obj包装在过滤器中?
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 |数学:&#39;小区&#39;}}
答案 6 :(得分:6)
答案 7 :(得分:6)
使用Angular进行简单数学运算的最简单方法是直接在HTML标记中根据需要进行单独绑定,假设您不需要在页面上进行批量计算。这是一个例子:
{{(data.input/data.input2)| number}}
在这种情况下,您只需在()中进行数学运算,然后使用过滤器|得到一个答案。这里有关于将角度数字格式化为文本的更多信息:
答案 8 :(得分:4)
将全局Math对象绑定到范围上(记住使用$ window not window)
sed -r 's/^([^ ]+ ){2}//' test.txt
在HTML中使用绑定:
$scope.abs = $window.Math.abs;
或者为您之后的特定数学函数创建一个过滤器:
<p>Distance from zero: {{abs(distance)}}</p>
在HTML中使用过滤器:
module.filter('abs', ['$window', function($window) {
return function(n) {
return $window.Math.abs($window.parseInt(n));
};
});
答案 9 :(得分:2)
这看起来不像是一种非常有角度的方式。我不完全确定它为什么不起作用,但你可能需要访问范围才能使用这样的函数。
我的建议是创建一个过滤器。这是Angular方式。
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
然后在你的HTML中执行以下操作:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
答案 10 :(得分:1)
number
过滤器使用千位分隔符格式化数字,因此它不是严格意义上的数学函数。
此外,它的十进制限制器&#39;没有ceil
任何切碎的小数(因为其他一些答案会让你相信),而是round
他们。
因此,对于您想要的任何数学函数,您可以注入它(比注入整个Math对象更容易模拟),如下所示:
myModule.filter('ceil', function () {
return Math.ceil;
});
无需将其包装在另一个函数中。
答案 11 :(得分:0)
这或多或少是三个答案的总结(SaraInésCalderón,klaxon和Gothburz),但由于他们都添加了一些重要内容,我认为值得加入解决方案并添加更多解释。
考虑您的示例,您可以使用以下方法在模板中进行计算:
{{ 100 * (count/total) }}
但是,这可能会产生大量的小数位,所以使用过滤器是一个很好的方法:
{{ 100 * (count/total) | number }}
默认情况下,数字过滤器会leave up to three fractional digits,这是 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>
最后要提到的是,如果您依赖外部数据源,提供正确的后备值可能是一种好习惯(否则您可能会看到NaN或没有在您的网站上):
{{ (100 * (count/total) | number:0) || 0 }}
旁注:根据您的规格,您甚至可以更精确地使用后备/定义较低级别的后备(例如{{(100 * (count || 10)/ (total || 100) | number:2)}}
)。虽然,这可能并不总是有意义。
答案 12 :(得分:0)
使用管道的Angular Typescript示例。
math.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'math',
})
export class MathPipe implements PipeTransform {
transform(value: number, args: any = null):any {
if(value) {
return Math[args](value);
}
return 0;
}
}
添加到@NgModule声明
@NgModule({
declarations: [
MathPipe,
然后在你的模板中使用:
{{(100*count/total) | math:'round'}}