Est-il possible d'utiliser des fonctions mathématiques dans les liaisons AngularJS?
par exemple.
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Ce violon montre le problème
Vous devez injecter Math
dans votre oscilloscope, si vous devez l’utiliser en tant que $scope
ne rien connaître de Math.
Manière la plus simple, vous pouvez faire
$scope.Math = window.Math;
dans votre contrôleur . Une façon angulaire de le faire correctement serait de créer un service mathématique, je suppose.
Bien que la réponse acceptée soit correcte, vous pouvez injecter Math
pour l’utiliser en mode angulaire, mais pour ce problème particulier, la méthode la plus classique/angulaire est le filtre numérique:
<p>The percentage is {{(100*count/total)| number:0}}%</p>
Vous pouvez en savoir plus sur le filtre number
ici: http://docs.angularjs.org/api/ng/filter/number
Je pense que la meilleure façon de le faire est de créer un filtre, comme ceci:
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
alors le balisage ressemble à ceci:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Violon mis à jour: http://jsfiddle.net/BB4T4/
C’est une question poilue à laquelle répondre, car vous n’avez pas donné le contexte complet de ce que vous faites. La réponse acceptée fonctionnera, mais dans certains cas, les performances seront médiocres. Ça, et ça va être plus difficile à tester.
Si vous faites cela dans le cadre d'une forme statique, c'est bien. La réponse acceptée fonctionnera, même si ce n’est pas facile à tester, et c’est grave.
Vous voudrez conserver toute "logique métier" (c'est-à-dire une logique modifiant l'affichage des données) dans vos vues. Cela vous permet de tester votre logique et d'éviter de coupler étroitement votre contrôleur et votre vue. Théoriquement, vous devriez pouvoir pointer votre contrôleur vers une autre vue et utiliser les mêmes valeurs à partir des étendues. (si ça a du sens).
Vous voudrez également considérer que tous les appels de fonction à l'intérieur d'une liaison (tels que {{}}
ou ng-bind
ou ng-bind-html
) devront être évalués sur every digest , car angular n'a aucun moyen de savoir si la valeur a changé ou pas comme il le ferait avec une propriété sur la portée.
La méthode "angulaire" consiste à mettre en cache la valeur d'une propriété dans l'étendue de la modification à l'aide d'un événement ng-change ou même d'une surveillance $.
Par exemple avec une forme statique:
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.
});
});
Une meilleure option consiste à utiliser:
{{(100*score/questionCounter) || 0 | number:0}}
Il définit la valeur par défaut de l'équation sur 0 dans le cas où les valeurs ne sont pas initialisées.
Pourquoi ne pas envelopper l'objet mathématique entier dans un filtre?
var app = angular.module('fMathFilters',[]);
function math() {
return function(input,arg) {
if(input) {
return Math[arg](input);
}
return 0;
}
}
return app.filter('math',[math]);
et à utiliser:
{{number_var | maths: 'ceil'}}
Le moyen le plus simple de faire des calculs simples avec Angular est directement dans le balisage HTML pour les liaisons individuelles en fonction des besoins, en supposant que vous n’ayez pas besoin de faire des calculs en masse sur votre page. Voici un exemple:
{{(data.input/data.input2)| number}}
Dans ce cas, il vous suffit de faire le calcul dans la (), puis d'utiliser un filtre | pour obtenir un numéro de réponse. Voici plus d'informations sur le formatage des nombres angulaires en texte:
Si vous cherchez à faire un tour simple en angulaire, vous pouvez facilement définir le filtre dans votre expression. Par exemple:
{{ val | number:0 }}
Voir ceci CodePen example & pour les autres options de filtrage de numéros.
Soit lier l’objet mathématique global à l’étendue (souvenez-vous d’utiliser $ window not window)
$scope.abs = $window.Math.abs;
Utilisez la liaison dans votre code HTML:
<p>Distance from zero: {{abs(distance)}}</p>
Ou créez un filtre pour la fonction mathématique spécifique que vous recherchez:
module.filter('abs', ['$window', function($window) {
return function(n) {
return $window.Math.abs($window.parseInt(n));
};
});
Utilisez le filtre dans votre code HTML:
<p>Distance from zero: {{distance | abs}}</p>
Cela ne ressemble pas à une façon très angulaire de le faire. Je ne suis pas tout à fait sûr pourquoi cela ne fonctionne pas, mais vous auriez probablement besoin d'accéder à la portée pour pouvoir utiliser une telle fonction.
Ma suggestion serait de créer un filtre. C'est la manière angulaire.
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
Ensuite, dans votre code HTML, procédez comme suit:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Exemple de TypeScript angulaire utilisant un tuyau.
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;
}
}
Ajouter aux déclarations @NgModule
@NgModule({
declarations: [
MathPipe,
puis utilisez dans votre modèle comme suit:
{{(100*count/total) | math:'round'}}
Le filtre number
formate le nombre avec des séparateurs de milliers, de sorte qu'il ne s'agit pas strictement d'une fonction mathématique.
De plus, son «limiteur» décimal ne ceil
pas de décimales hachées (comme le suggèrent certaines autres réponses), mais plutôt round
s.
Donc, pour n'importe quelle fonction mathématique que vous voulez, vous pouvez l'injecter (plus facile à simuler que d'injecter tout l'objet Math) comme ceci:
myModule.filter('ceil', function () {
return Math.ceil;
});
Pas besoin de l'envelopper dans une autre fonction non plus.