¿Hay alguna manera de usar funciones matemáticas en enlaces AngularJS?
p.ej
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Este violín muestra el problema
private Math = Math;y puede usarlo.
¿Hay alguna manera de usar funciones matemáticas en enlaces AngularJS?
p.ej
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Este violín muestra el problema
private Math = Math;y puede usarlo.
Respuestas:
Debe inyectar Mathen su ámbito, si necesita usarlo, ya
$scopeque no sabe nada sobre matemáticas.
De la manera más simple, puedes hacer
$scope.Math = window.Math;
en su controlador Supongo que una forma angular de hacer esto correctamente sería crear un servicio matemático.
formatting, así que use filtro en su lugar
Si bien la respuesta aceptada es correcta, puede inyectarla Mathpara 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 numberfiltro aquí: http://docs.angularjs.org/api/ng/filter/number
{{1234.567|number:2}}se representa como 1,234.57o 1 234,57. Si intenta pasarlo <input type="number" ng-value="1234.567|number:2">, vaciará la entrada, ya que el valor NO ES UN NÚMERO CORRECTO, sino una representación de cadena dependiente de la configuración regional.
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 ve así:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Violín actualizado: http://jsfiddle.net/BB4T4/
Esta es una pregunta difícil de responder, porque no dio el contexto completo de lo que está 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á haciendo esto como parte de una forma estática, está bien. La respuesta aceptada funcionará, incluso si no es fácil de evaluar, y es extraña.
Querrá mantener cualquier "lógica de negocios" (es decir, lógica que altere los datos que se mostrarán) fuera de sus vistas. Esto es para que pueda probar su lógica de forma unitaria, y para que no termine estrechamente acoplando 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á tener en cuenta que cualquier función llamada dentro de un enlace (como {{}}o ng-bindo ng-bind-html) tendrá que evaluarse 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 del cambio utilizando un evento ng-change 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>
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.
});
});
$windowya que parece funcionar solo con el plan Math.round()?
Mathpruebas. Alternativamente, puede crear un servicio matemático e inyectarlo.
¿Por qué no envolver todo el obj matemático 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 para usar:
{{number_var | matemática: 'ceil'}}
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.
La forma más fácil de hacer cálculos matemáticos simples con Angular es directamente en el marcado HTML para enlaces individuales según sea necesario, suponiendo que no necesite hacer cálculos masivos en su página. Aquí hay un ejemplo:
{{(data.input/data.input2)| number}}
En este caso, solo hace los cálculos en () y luego usa un filtro | para obtener una respuesta numérica Aquí hay más información sobre cómo formatear números angulares como texto:
Puede vincular el objeto matemático global al ámbito (recuerde usar $ window, no window)
$scope.abs = $window.Math.abs;
Use el enlace en su HTML:
<p>Distance from zero: {{abs(distance)}}</p>
O cree un filtro para la función matemática específica que busca:
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>
Eso no parece una forma muy angular de hacerlo. No estoy completamente seguro de por qué no funciona, pero es probable que necesite acceder al alcance 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>
El numberfiltro formatea el número con miles de separadores, por lo que no es estrictamente una función matemática.
Además, su 'limitador' decimal no tiene ceildecimales cortados (como algunas otras respuestas lo llevarían a creer), sino más bien su respuesta round.
Entonces, para cualquier función matemática que desee, puede inyectarla (más fácil de burlarse que inyectar todo el objeto matemático) de esta manera:
myModule.filter('ceil', function () {
return Math.ceil;
});
No es necesario envolverlo en otra función tampoco.
Esto es más o menos un resumen de tres respuestas (por Sara Inés Calderón, klaxon y Gothburz), pero como todos agregaron algo importante, considero que vale la pena unir las soluciones y agregar más explicaciones.
Considerando 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 manera de hacerlo:
{{ 100 * (count/total) | number }}
Por defecto, el filtro de números dejará hasta tres dígitos fraccionarios , aquí es donde el argumento fraccionSize resulta 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:
Lo último que hay que mencionar, si confía en una fuente de datos externa, probablemente sea una buena práctica proporcionar un valor de reserva 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, incluso puede ser más preciso con sus retrocesos / definir retrocesos en niveles más bajos (por ejemplo {{(100 * (count || 10)/ (total || 100) | number:2)}}). Sin embargo, esto no siempre tiene sentido.
Ejemplo de mecanografía angular usando una tubería.
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;
}
}
Agregar a las declaraciones de @NgModule
@NgModule({
declarations: [
MathPipe,
luego use en su plantilla de la siguiente manera:
{{(100*count/total) | math:'round'}}
<p>The percentage is {{(100*count/total)| number:0}}%</p>más en el comentario a continuación.