sintaxis - Funciones matemáticas en enlaces AngularJS
ng attr title (13)
¿Por qué no envolver todo el objeto de matemáticas en un 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]);
y utilizar:
{{number_var | matematicas: ''ceil''}}
¿Hay alguna forma de usar funciones matemáticas en los enlaces de AngularJS?
p.ej
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Este violín muestra el problema.
Creo que la mejor manera de hacerlo es creando un filtro, como este:
myModule.filter(''ceil'', function() {
return function(input) {
return Math.ceil(input);
};
});
entonces el marcado se parece a esto:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Fiddle actualizado: http://jsfiddle.net/BB4T4/
Ejemplo de escritura angular con un tubo.
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;
}
}
Añadir a las declaraciones de @NgModule
@NgModule({
declarations: [
MathPipe,
luego use en su plantilla como tal:
{{(100*count/total) | math:''round''}}
El filtro de number
formatea el número con miles de separadores, por lo que no es estrictamente una función matemática.
Más aún, su "limitador" decimal no produce ningún decimal cortado (como algunas otras respuestas lo harían creer), sino que los round
.
Por lo tanto, para cualquier función matemática que desee, puede inyectarla (más fácil de simular que inyectar todo el objeto matemático) de esta manera:
myModule.filter(''ceil'', function () {
return Math.ceil;
});
Tampoco es necesario envolverlo en otra función.
Eso no parece ser una forma muy angular de hacerlo. No estoy completamente seguro de por qué no funciona, pero es probable que necesites acceder al ámbito para usar una función como esa.
Mi sugerencia sería crear un filtro. Esa es la forma angular.
myModule.filter(''ceil'', function() {
return function(input) {
return Math.ceil(input);
};
});
Luego en tu HTML haz esto:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Este es un problema para responder, porque no diste todo el contexto de lo que estás haciendo. La respuesta aceptada funcionará, pero en algunos casos causará un bajo rendimiento. Eso, y va a ser más difícil de probar.
Si estás haciendo esto como parte de una forma estática, está bien. La respuesta aceptada funcionará, incluso si no es fácil de probar, y es muy delicada.
Si quieres ser "angular" sobre esto:
Usted querrá mantener cualquier "lógica de negocios" (es decir, la lógica que altera los datos que se mostrarán) fuera de sus vistas. Esto es para que pueda probar su lógica por unidad y, por lo tanto, no termine de acoplar estrechamente su controlador y su vista. Teóricamente, debería poder apuntar su controlador a otra vista y usar los mismos valores de los ámbitos. (Si eso tiene sentido).
También querrá considerar que cualquier función llamada dentro de un enlace (como {{}}
o ng-bind
o ng-bind-html
) tendrá que ser evaluada en cada resumen , porque angular no tiene forma de saber si el valor ha cambiado o no como lo haría con una propiedad en el alcance.
La forma "angular" de hacer esto sería almacenar en caché el valor de una propiedad en el alcance en el cambio utilizando un evento de cambio de ng o incluso un $ watch.
Por ejemplo con una forma estática:
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>
Y ahora puedes probarlo!
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.
});
});
Esto es más o menos un resumen de tres respuestas (por Sara Inés Calderón, klaxon y Gothburz), pero como todas agregaron algo importante, considero que vale la pena unir las soluciones y agregar más explicaciones.
Teniendo en cuenta su ejemplo, puede hacer cálculos en su plantilla usando:
{{ 100 * (count/total) }}
Sin embargo, esto puede resultar en una gran cantidad de decimales, por lo que usar filtros es una buena forma de proceder:
{{ 100 * (count/total) | number }}
Por defecto, el filtro de números dejará hasta tres dígitos fraccionarios , aquí es donde el argumento fractionSize es bastante útil ( {{ 100 * (count/total) | number:fractionSize }}
), que en su caso sería:
{{ 100 * (count/total) | number:0 }}
Esto también redondeará el resultado ya:
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>
Por último, si confía en una fuente de datos externa, probablemente sea una buena práctica proporcionar un valor de respaldo adecuado (de lo contrario, puede ver NaN o nada en su sitio):
{{ (100 * (count/total) | number:0) || 0 }}
Nota al margen: Dependiendo de sus especificaciones, puede incluso ser más preciso con sus reservas / definir reservas en niveles más bajos (por ejemplo, {{(100 * (count || 10)/ (total || 100) | number:2)}}
). Sin embargo, esto no siempre puede tener sentido ...
La forma más fácil de hacer cálculos simples con Angular es directamente en el marcado HTML para enlaces individuales según sea necesario, asumiendo que no necesita realizar cálculos en masa en su página. Aquí hay un ejemplo:
{{(data.input/data.input2)| number}}
En este caso, simplemente haga los cálculos en () y luego use un filtro | para obtener una respuesta número. Aquí hay más información sobre el formato de los números angulares como texto:
Mejor opción es usar:
{{(100*score/questionCounter) || 0 | number:0}}
Establece el valor predeterminado de la ecuación en 0 en el caso en que los valores no se inicializan.
O vincule el objeto matemático global al ámbito (recuerde usar $ window no window)
$scope.abs = $window.Math.abs;
Usa el enlace en tu HTML:
<p>Distance from zero: {{abs(distance)}}</p>
O crea un filtro para la función matemática específica que estás buscando:
module.filter(''abs'', [''$window'', function($window) {
return function(n) {
return $window.Math.abs($window.parseInt(n));
};
});
Usa el filtro en tu HTML:
<p>Distance from zero: {{distance | abs}}</p>
Si bien la respuesta aceptada es correcta, puede inyectar Math
para usarla en angular, para este problema en particular, la forma más convencional / angular es el filtro de números:
<p>The percentage is {{(100*count/total)| number:0}}%</p>
Puede leer más sobre el filtro de number
aquí: http://docs.angularjs.org/api/ng/filter/number
Si está buscando hacer una ronda simple en Angular, puede configurar fácilmente el filtro dentro de su expresión. Por ejemplo:
{{ val | number:0 }}
Vea este ejemplo de CodePen y para otras opciones de filtro de números.
Tiene que inyectar Math
en su ámbito de aplicación, si necesita usarlo ya que $scope
no sabe nada de Matemáticas.
La forma más sencilla, puedes hacerlo.
$scope.Math = window.Math;
en su controlador La forma angular de hacer esto correctamente sería crear un servicio matemático, supongo.