Existe uma maneira de usar funções matemáticas nas ligações do AngularJS?
por exemplo
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Este violino mostra o problema
private Math = Math;
e você pode usá-lo.
Existe uma maneira de usar funções matemáticas nas ligações do AngularJS?
por exemplo
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Este violino mostra o problema
private Math = Math;
e você pode usá-lo.
Respostas:
Você precisa injetar Math
no seu escopo, se não precisar usá-lo, pois
$scope
não sabe nada sobre matemática.
Maneira mais simples, você pode fazer
$scope.Math = window.Math;
no seu controlador. Uma maneira angular de fazer isso corretamente seria criar um serviço de matemática, eu acho.
formatting
, então use o filtro.
Enquanto a resposta aceita é correta, você pode injetar Math
para usá-la em ângulo, para esse problema em particular, a maneira mais convencional / angular é o filtro numérico:
<p>The percentage is {{(100*count/total)| number:0}}%</p>
Você pode ler mais sobre o number
filtro aqui: http://docs.angularjs.org/api/ng/filter/number
{{1234.567|number:2}}
processa como 1,234.57
ou 1 234,57
. Se você tentar passá-lo, <input type="number" ng-value="1234.567|number:2">
você esvaziará a entrada, pois o valor NÃO É UM NÚMERO CORRETO, mas a representação de sequência dependente da localidade.
Eu acho que a melhor maneira de fazer isso é criando um filtro, assim:
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
então a marcação fica assim:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Violino atualizado: http://jsfiddle.net/BB4T4/
Essa é uma pergunta difícil de responder, porque você não deu o contexto completo do que está fazendo. A resposta aceita funcionará, mas em alguns casos causará baixo desempenho. Isso, e será mais difícil de testar.
Se você estiver fazendo isso como parte de um formulário estático, tudo bem. A resposta aceita funcionará, mesmo que não seja fácil de testar, e seja hinky.
Você deseja manter qualquer "lógica comercial" (isto é, lógica que altera os dados a serem exibidos) fora de suas visualizações. Isso é para que você possa testar sua lógica de unidade e não acabar acoplando firmemente seu controlador e sua visão. Teoricamente, você deve poder apontar seu controlador para outra visão e usar os mesmos valores dos escopos. (se isso faz sentido).
Você também deve considerar que todas as chamadas de função dentro de uma ligação (como {{}}
ou ng-bind
ou ng-bind-html
) terão que ser avaliadas em todos os resumos , porque o angular não tem como saber se o valor foi alterado ou não como uma propriedade no escopo.
A maneira "angular" de fazer isso seria armazenar em cache o valor em uma propriedade no escopo da mudança usando um evento ng-change ou mesmo um $ watch.
Por exemplo, com um formulário estático:
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
vez que parece funcionar apenas com um plano Math.round()
?
Math
testes. Como alternativa, você pode criar um serviço de matemática e injetá-lo.
Por que não agrupar todo o objeto de matemática em um filtro?
var app = angular.module('fMathFilters',[]);
function math() {
return function(input,arg) {
if(input) {
return Math[arg](input);
}
return 0;
}
}
return app.filter('math',[math]);
e usar:
{{number_var | math: 'ceil'}}
Se você deseja fazer uma rodada simples em Angular, pode definir facilmente o filtro dentro de sua expressão. Por exemplo:
{{ val | number:0 }}
Veja este exemplo do CodePen e para outras opções de filtro numérico.
A maneira mais fácil de fazer contas simples com o Angular é diretamente na marcação HTML para ligações individuais, conforme necessário, supondo que você não precise fazer cálculos em massa na sua página. Aqui está um exemplo:
{{(data.input/data.input2)| number}}
Nesse caso, basta fazer as contas em () e usar um filtro | para obter uma resposta numérica. Veja mais informações sobre a formatação de números angulares como texto:
Ligue o objeto Math global ao escopo (lembre-se de usar $ window not window)
$scope.abs = $window.Math.abs;
Use a ligação no seu HTML:
<p>Distance from zero: {{abs(distance)}}</p>
Ou crie um filtro para a função matemática específica que você procura:
module.filter('abs', ['$window', function($window) {
return function(n) {
return $window.Math.abs($window.parseInt(n));
};
});
Use o filtro no seu HTML:
<p>Distance from zero: {{distance | abs}}</p>
Isso não parece uma maneira muito angular de fazer isso. Não sei ao certo por que isso não funciona, mas você provavelmente precisará acessar o escopo para usar uma função como essa.
Minha sugestão seria criar um filtro. Essa é a maneira angular.
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
Então, no seu HTML, faça o seguinte:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
O number
filtro formata o número com separadores de milhares, portanto, não é estritamente uma função matemática.
Além disso, o seu 'limitador' decimal não ceil
decimais cortados (como algumas outras respostas levariam você a acreditar), mas sim round
preenchê-los.
Portanto, para qualquer função matemática que você desejar, você pode injetá-la (mais fácil de zombar do que injetar todo o objeto Math) da seguinte maneira:
myModule.filter('ceil', function () {
return Math.ceil;
});
Também não é necessário envolvê-lo em outra função.
Este é mais ou menos um resumo de três respostas (de Sara Inés Calderón, klaxon e Gothburz), mas como todas adicionaram algo importante, considero que vale a pena juntar as soluções e acrescentar mais explicações.
Considerando o seu exemplo, você pode fazer cálculos no seu modelo usando:
{{ 100 * (count/total) }}
No entanto, isso pode resultar em muitas casas decimais, portanto, usar filtros é um bom caminho a seguir:
{{ 100 * (count/total) | number }}
Por padrão, o filtro numérico deixará até três dígitos fracionários ; é nesse ponto que o argumento da fraçãoSize é bastante útil ( {{ 100 * (count/total) | number:fractionSize }}
), que no seu caso seria:
{{ 100 * (count/total) | number:0 }}
Isso também arredondará o resultado já:
A última coisa a mencionar, se você confiar em uma fonte de dados externa, provavelmente é uma boa prática fornecer um valor de fallback adequado (caso contrário, você poderá ver NaN ou nada no seu site):
{{ (100 * (count/total) | number:0) || 0 }}
Nota: Dependendo das suas especificações, você pode até ser mais preciso com seus fallbacks / definir fallbacks em níveis mais baixos (por exemplo {{(100 * (count || 10)/ (total || 100) | number:2)}}
). No entanto, isso nem sempre faz sentido ..
Exemplo de texto datilografado angular usando um 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;
}
}
Adicionar às declarações @NgModule
@NgModule({
declarations: [
MathPipe,
use no seu modelo da seguinte maneira:
{{(100*count/total) | math:'round'}}
<p>The percentage is {{(100*count/total)| number:0}}%</p>
mais nos comentários abaixo.