236

有没有办法在 AngularJS 绑定中使用数学函数?

例如

<p>The percentage is {{Math.round(100*count/total)}}%</p>

这个小提琴显示了问题

http://jsfiddle.net/ricick/jtA99/1/

4

13 回答 13

333

Math如果您需要将其用作 $scope对数学一无所知的情况,则必须将其注入您的范围。

最简单的方法,你可以

$scope.Math = window.Math;

在您的控制器中。我猜,正确执行此操作的 Angular 方法是创建一个数学服务。

于 2012-10-05T06:12:01.060 回答
307

虽然公认的答案是正确的,您可以注入Math以角度使用它,但对于这个特定问题,更传统/角度的方式是数字过滤器:

<p>The percentage is {{(100*count/total)| number:0}}%</p>

您可以在此处阅读有关number过滤器的更多信息:http: //docs.angularjs.org/api/ng/filter/number

于 2013-04-26T17:20:15.283 回答
62

我认为最好的方法是创建一个过滤器,如下所示:

myModule.filter('ceil', function() {
    return function(input) {
        return Math.ceil(input);
    };
});

那么标记看起来像这样:

<p>The percentage is {{ (100*count/total) | ceil }}%</p>

更新小提琴:http: //jsfiddle.net/BB4T4/

于 2014-06-04T06:41:41.203 回答
37

这是一个很难回答的问题,因为你没有给出你正在做的事情的完整背景。接受的答案会起作用,但在某些情况下会导致性能不佳。那,它将更难测试。

如果您将其作为静态表单的一部分进行,那很好。接受的答案会起作用,即使它不容易测试,而且很奇怪。

如果您想对此“有角度”:

您将希望将任何“业务逻辑”(即更改要显示的数据的逻辑)保留在您的视图之外。这样您就可以对您的逻辑进行单元测试,因此您最终不会将控制器和视图紧密耦合。从理论上讲,您应该能够将控制器指向另一个视图并使用范围中的相同值。(如果这有意义的话)。

您还需要考虑绑定内部的任何函数调用(例如{{}}orng-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.
  });
});
于 2013-04-26T17:52:13.993 回答
8

更好的选择是使用:

{{(100*score/questionCounter) || 0 | number:0}}

在未初始化值的情况下,它将方程的默认值设置为 0。

于 2015-12-13T03:00:37.293 回答
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 | 数学:'ceil'}}

于 2016-11-01T15:18:33.180 回答
6

如果你想在 Angular 中做一个简单的回合,你可以很容易地在你的表达式中设置过滤器。例如:

{{ val | number:0 }}

有关其他数字过滤器选项,请参阅此CodePen示例和。

关于使用数字过滤器的 Angular 文档

于 2015-10-22T22:05:02.010 回答
6

假设您不需要在页面上进行大规模计算,使用 Angular 进行简单数学运算的最简单方法是直接在 HTML 标记中根据需要进行单个绑定。这是一个例子:

{{(data.input/data.input2)| number}} 

在这种情况下,您只需在 () 中进行数学运算,然后使用过滤器 | 得到一个数字答案。以下是有关将 Angular 数字格式化为文本的更多信息:

https://docs.angularjs.org/api/ng/filter

于 2016-02-02T20:51:10.420 回答
5

将全局数学对象绑定到范围(记住使用 $window 而不是窗口)

$scope.abs = $window.Math.abs;

在 HTML 中使用绑定:

<p>Distance from zero: {{abs(distance)}}</p>

或者为您所追求的特定数学函数创建一个过滤器:

module.filter('abs', ['$window', function($window) {
  return function(n) {
    return $window.Math.abs($window.parseInt(n));
  };
});

在您的 HTML 中使用过滤器:

<p>Distance from zero: {{distance | abs}}</p>
于 2015-08-12T14:48:35.973 回答
3

这看起来不像是一种非常 Angular 的方式。我不完全确定它为什么不起作用,但您可能需要访问范围才能使用这样的功能。

我的建议是创建一个过滤器。这就是 Angular 的方式。

myModule.filter('ceil', function() {
    return function(input) {
        return Math.ceil(input);
    };
});

然后在您的 HTML 中执行以下操作:

<p>The percentage is {{ (100*count/total) | ceil }}%</p>
于 2017-01-21T14:40:50.980 回答
2

过滤器使用number千位分隔符格式化数字,因此它不是严格的数学函数。

此外,它的小数“限制器”没有ceil任何小数位(正如其他一些答案会让你相信的那样),而是rounding 他们。

因此,对于您想要的任何数学函数,您可以像这样注入它(比注入整个 Math 对象更容易模拟):

myModule.filter('ceil', function () {
  return Math.ceil;
});

也不需要将它包装在另一个函数中。

于 2017-08-30T22:43:28.440 回答
0

这或多或少是对三个答案的总结(由 Sara Inés Calderón、klaxon 和 Gothburz 撰写),但由于它们都添加了一些重要的东西,我认为值得加入这些解决方案并添加更多解释。

考虑到您的示例,您可以使用以下方法在模板中进行计算:

{{ 100 * (count/total) }}

但是,这可能会导致很多小数位,因此使用过滤器是一个不错的方法:

{{ 100 * (count/total) | number }}

默认情况下,数字过滤器将保留最多三个小数位,这是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)}})。虽然,这可能并不总是有意义..

于 2016-12-09T15:06:16.277 回答
0

使用管道的 Angular Typescript 示例。

数学管道.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'}}
于 2018-02-17T11:31:31.683 回答