AngularJSバインディングで数学関数を使用する方法はありますか?
例えば
<p>The percentage is {{Math.round(100*count/total)}}%</p>
このフィドルは問題を示しています
private Math = Math;
を定義して使用できます。
AngularJSバインディングで数学関数を使用する方法はありますか?
例えば
<p>The percentage is {{Math.round(100*count/total)}}%</p>
このフィドルは問題を示しています
private Math = Math;
を定義して使用できます。
回答:
Mathについて何も知らないMath
ように使用する必要がある場合は、スコープに挿入する必要があります
$scope
。
最も簡単な方法は、あなたができる
$scope.Math = window.Math;
コントローラで。これを正しく行うための角度的な方法は、Mathサービスを作成することだと思います。
formatting
、代わりにフィルターを使用してください。
受け入れられた答えはあなたがMath
それを角度で使用するために注入することができるのは正しいですが、この特定の問題では、より一般的/角度的な方法は数値フィルターです:
<p>The percentage is {{(100*count/total)| number:0}}%</p>
number
フィルターの詳細については、http://docs.angularjs.org/api/ng/filter/numberを参照してください。
{{1234.567|number:2}}
としてレンダリングします。これを渡そうとすると、入力は空になります。値は正しい数字ではなく、ロケールに依存する文字列表現だからです。1,234.57
1 234,57
<input type="number" ng-value="1234.567|number:2">
これを行う最良の方法は、次のようなフィルターを作成することです。
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
マークアップは次のようになります。
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
更新されたフィドル:http : //jsfiddle.net/BB4T4/
あなたがしていることの完全なコンテキストを提供しなかったので、これは答える毛深いものです。受け入れられた答えは機能しますが、場合によってはパフォーマンスが低下します。それは、テストするのが難しくなるでしょう。
静的フォームの一部としてこれを行っている場合は、問題ありません。簡単にテストできなくても、受け入れられた答えは機能します。
ビューから「ビジネスロジック」(つまり、表示されるデータを変更するロジック)を除外する必要があります。これは、ロジックを単体テストできるようにするためであり、コントローラーとビューを緊密に結合することにはなりません。理論的には、コントローラーを別のビューに向け、スコープの同じ値を使用できるはずです。(それが理にかなっている場合)。
バインディング内の関数呼び出し({{}}
またはor 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.
});
});
$window
、それは計画だけで動作するように見えるので、なぜ先頭に追加するのかと思いMath.round()
ますか?
Math
、テスト用のモックをより簡単に作成できます。あるいは、Mathサービスを作成して、それを注入することもできます。
Angularで単純なラウンドを実行する場合は、式内にフィルターを簡単に設定できます。例えば:
{{ val | number:0 }}
他の数値フィルターオプションについては、このCodePenの例&を参照してください。
Angularで簡単な計算を行う最も簡単な方法は、ページで大量の計算を行う必要がないと想定して、必要に応じて個々のバインディングのHTMLマークアップで直接行うことです。次に例を示します。
{{(data.input/data.input2)| number}}
この場合、()で計算を行い、フィルターを使用します。数の答えを得るために。角数値をテキストとしてフォーマットする方法の詳細は次のとおりです。
グローバルMathオブジェクトをスコープにバインドします(ウィンドウではなく$ 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>
それはそれを行う非常に角度のある方法のようには見えません。それが機能しない理由は完全にはわかりませんが、そのような関数を使用するには、おそらくスコープにアクセスする必要があります。
私の提案は、フィルターを作成することです。これがAngularの方法です。
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
次に、HTMLで次のようにします。
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
number
それは厳密に数学の機能はありませんので、フィルターは、桁区切りで番号をフォーマットします。
さらに、その10進数の「リミッター」はceil
切り刻まれた10進数ではなく(他のいくつかの答えはあなたを信じさせるでしょう)、むしろround
それらを使用します。
したがって、任意の数学関数について、次のように関数を注入できます(Mathオブジェクト全体を注入するよりもモックする方が簡単です)。
myModule.filter('ceil', function () {
return Math.ceil;
});
別の関数でラップする必要もありません。
これは多かれ少なかれ3つの回答の要約です(SaraInésCalderón、klaxon、およびGothburzによる)。これらはすべて重要なことを追加したので、解決策に加わって説明を追加する価値があると思います。
あなたの例を考えると、あなたはテンプレートを使って計算を行うことができます:
{{ 100 * (count/total) }}
ただし、これにより小数点以下の桁数が多くなる可能性があるため、フィルターを使用することをお勧めします。
{{ 100 * (count/total) | number }}
デフォルトでは、数値フィルターは最大3桁の小数桁を残します。これは、fractionSize引数が非常に便利({{ 100 * (count/total) | number:fractionSize }}
)になる場合です。
{{ 100 * (count/total) | number:0 }}
これにより、結果もすでに丸められます。
最後に、外部データソースに依存している場合は、適切なフォールバック値を提供することをお勧めします(そうしないと、サイトにNaNまたは何も表示されない場合があります)。
{{ (100 * (count/total) | number:0) || 0 }}
補足:仕様によっては、フォールバックをより正確にしたり、より低いレベルでフォールバックを定義したりすることもできます(例:){{(100 * (count || 10)/ (total || 100) | number:2)}}
。ただし、これが必ずしも意味があるとは限りません。
パイプを使用した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'}}
<p>The percentage is {{(100*count/total)| number:0}}%</p>
しないようにすることです。