Gibt es eine Möglichkeit, mathematische Funktionen in AngularJS-Bindungen zu verwenden?
z.B
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Diese Geige zeigt das Problem
private Math = Math;
und Sie können es verwenden.
Gibt es eine Möglichkeit, mathematische Funktionen in AngularJS-Bindungen zu verwenden?
z.B
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Diese Geige zeigt das Problem
private Math = Math;
und Sie können es verwenden.
Antworten:
Sie müssen Math
in Ihr Zielfernrohr injizieren , wenn Sie es verwenden müssen, da Sie
$scope
nichts über Mathematik wissen.
Am einfachsten geht das
$scope.Math = window.Math;
in Ihrem Controller. Ein eckiger Weg, dies richtig zu machen, wäre, einen Mathe-Dienst zu erstellen, denke ich.
formatting
, verwenden Sie stattdessen Filter.
Während die akzeptierte Antwort richtig ist, dass Sie injizieren können, Math
um sie im Winkel zu verwenden, ist für dieses spezielle Problem der Zahlenfilter der konventionellere / eckigere Weg:
<p>The percentage is {{(100*count/total)| number:0}}%</p>
Weitere Informationen zum number
Filter finden Sie hier: http://docs.angularjs.org/api/ng/filter/number
{{1234.567|number:2}}
rendert als 1,234.57
oder 1 234,57
. Wenn Sie versuchen, es an <input type="number" ng-value="1234.567|number:2">
Sie zu übergeben, wird die Eingabe leer, da der Wert KEINE RICHTIGE NUMMER, sondern eine vom Gebietsschema abhängige Zeichenfolgendarstellung ist.
Ich denke, der beste Weg, dies zu tun, besteht darin, einen Filter wie folgt zu erstellen:
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
dann sieht das Markup folgendermaßen aus:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Aktualisierte Geige: http://jsfiddle.net/BB4T4/
Dies ist eine haarige Frage, weil Sie nicht den vollständigen Kontext Ihrer Arbeit angegeben haben. Die akzeptierte Antwort funktioniert, führt jedoch in einigen Fällen zu einer schlechten Leistung. Das und es wird schwieriger zu testen sein.
Wenn Sie dies als Teil eines statischen Formulars tun, ist das in Ordnung. Die akzeptierte Antwort wird funktionieren, auch wenn es nicht einfach zu testen ist und es schwierig ist.
Sie sollten jede "Geschäftslogik" (dh Logik, die die anzuzeigenden Daten ändert) aus Ihren Ansichten heraushalten. Auf diese Weise können Sie Ihre Logik einem Unit-Test unterziehen und Ihren Controller und Ihre Ansicht nicht eng miteinander verbinden. Theoretisch sollten Sie in der Lage sein, Ihren Controller auf eine andere Ansicht zu richten und dieselben Werte aus den Bereichen zu verwenden. (wenn das Sinn macht).
Sie sollten auch berücksichtigen, dass alle Funktionsaufrufe innerhalb einer Bindung (wie {{}}
oder oder ng-bind
oder ng-bind-html
) bei jedem Digest ausgewertet werden müssen , da Angular nicht wissen kann, ob sich der Wert geändert hat oder nicht wie bei einer Eigenschaft auf den Umfang.
Die "eckige" Möglichkeit, dies zu tun, besteht darin, den Wert in einer Eigenschaft des Bereichs bei Änderung mithilfe eines ng-change-Ereignisses oder sogar einer $ watch zwischenzuspeichern.
Zum Beispiel mit einer statischen Form:
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
da es nur mit Plan zu funktionieren scheint Math.round()
?
Math
für Tests einfacher verspotten . Alternativ können Sie einen Mathedienst erstellen und einfügen.
Warum nicht das ganze Matheobjekt in einen Filter einwickeln?
var app = angular.module('fMathFilters',[]);
function math() {
return function(input,arg) {
if(input) {
return Math[arg](input);
}
return 0;
}
}
return app.filter('math',[math]);
und zu verwenden:
{{number_var | Mathe: 'Ceil'}}
Wenn Sie eine einfache Runde in Angular machen möchten, können Sie den Filter einfach in Ihrem Ausdruck festlegen. Beispielsweise:
{{ val | number:0 }}
In diesem CodePen- Beispiel & finden Sie weitere Optionen für den Nummernfilter .
Der einfachste Weg, mit Angular einfache Berechnungen durchzuführen, ist das HTML-Markup für einzelne Bindungen nach Bedarf, vorausgesetzt, Sie müssen keine Massenberechnungen auf Ihrer Seite durchführen. Hier ist ein Beispiel:
{{(data.input/data.input2)| number}}
In diesem Fall rechnen Sie einfach in () und verwenden dann einen Filter | um eine Antwort zu erhalten. Weitere Informationen zum Formatieren von Winkelnummern als Text:
Binden Sie entweder das globale Math-Objekt an den Bereich (denken Sie daran, $ window not window zu verwenden).
$scope.abs = $window.Math.abs;
Verwenden Sie die Bindung in Ihrem HTML:
<p>Distance from zero: {{abs(distance)}}</p>
Oder erstellen Sie einen Filter für die spezifische Math-Funktion, nach der Sie suchen:
module.filter('abs', ['$window', function($window) {
return function(n) {
return $window.Math.abs($window.parseInt(n));
};
});
Verwenden Sie den Filter in Ihrem HTML:
<p>Distance from zero: {{distance | abs}}</p>
Das sieht nicht nach einer sehr eckigen Art aus, es zu tun. Ich bin mir nicht ganz sicher, warum es nicht funktioniert, aber Sie müssten wahrscheinlich auf den Bereich zugreifen, um eine solche Funktion verwenden zu können.
Mein Vorschlag wäre, einen Filter zu erstellen. Das ist der Winkelweg.
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
Dann machen Sie in Ihrem HTML Folgendes:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Der number
Filter formatiert die Zahl mit Tausenden von Trennzeichen, sodass es sich nicht ausschließlich um eine mathematische Funktion handelt.
Darüber hinaus enthält der Dezimalbegrenzer ceil
keine abgeschnittenen Dezimalstellen (wie einige andere Antworten Sie glauben machen würden), sondern round
sie.
Für jede gewünschte mathematische Funktion können Sie sie wie folgt injizieren (einfacher zu verspotten als das gesamte mathematische Objekt zu injizieren):
myModule.filter('ceil', function () {
return Math.ceil;
});
Sie müssen es auch nicht in eine andere Funktion einbinden.
Dies ist mehr oder weniger eine Zusammenfassung von drei Antworten (von Sara Inés Calderón, Klaxon und Gothburz), aber da sie alle etwas Wichtiges hinzugefügt haben, halte ich es für sinnvoll, sich den Lösungen anzuschließen und weitere Erklärungen hinzuzufügen.
Anhand Ihres Beispiels können Sie Berechnungen in Ihrer Vorlage durchführen, indem Sie:
{{ 100 * (count/total) }}
Dies kann jedoch zu einer ganzen Reihe von Dezimalstellen führen. Daher ist die Verwendung von Filtern ein guter Weg:
{{ 100 * (count/total) | number }}
Standardmäßig hinterlässt der Zahlenfilter bis zu drei Bruchstellen . Hier ist das Argument fraktionSize sehr nützlich ( {{ 100 * (count/total) | number:fractionSize }}
). In Ihrem Fall wäre dies:
{{ 100 * (count/total) | number:0 }}
Dies wird auch das Ergebnis bereits abrunden:
Wenn Sie sich auf eine externe Datenquelle verlassen, ist es wahrscheinlich empfehlenswert , einen geeigneten Fallback-Wert anzugeben (andernfalls wird auf Ihrer Website möglicherweise NaN oder nichts angezeigt):
{{ (100 * (count/total) | number:0) || 0 }}
Nebenbemerkung: Abhängig von Ihren Spezifikationen können Sie möglicherweise sogar präziser mit Ihren Fallbacks umgehen / Fallbacks bereits auf niedrigeren Ebenen definieren (z {{(100 * (count || 10)/ (total || 100) | number:2)}}
. B. ). Dies ist jedoch möglicherweise nicht immer sinnvoll.
Angular Typescript Beispiel mit einer Pipe.
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;
}
}
Zu @ NgModule-Deklarationen hinzufügen
@NgModule({
declarations: [
MathPipe,
Verwenden Sie dann in Ihrer Vorlage wie folgt:
{{(100*count/total) | math:'round'}}
<p>The percentage is {{(100*count/total)| number:0}}%</p>
, mehr im Kommentar unten.