Esiste un modo per utilizzare le funzioni matematiche negli attacchi AngularJS?
per esempio
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Questo violino mostra il problema
private Math = Math;
e puoi usarlo.
Esiste un modo per utilizzare le funzioni matematiche negli attacchi AngularJS?
per esempio
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Questo violino mostra il problema
private Math = Math;
e puoi usarlo.
Risposte:
Devi iniettarti Math
nel tuo ambito, se hai bisogno di usarlo perché non
$scope
sai nulla di matematica.
Il modo più semplice, puoi farlo
$scope.Math = window.Math;
nel tuo controller. Immagino che un modo angolare per farlo correttamente sarebbe creare un servizio di matematica.
formatting
, quindi utilizzare il filtro.
Mentre la risposta accettata è corretta, è possibile iniettare Math
per usarla in angolare, per questo particolare problema, il modo più convenzionale / angolare è il filtro numerico:
<p>The percentage is {{(100*count/total)| number:0}}%</p>
Puoi leggere di più sul number
filtro qui: http://docs.angularjs.org/api/ng/filter/number
{{1234.567|number:2}}
viene visualizzato come 1,234.57
o 1 234,57
. Se si tenta di passarlo, <input type="number" ng-value="1234.567|number:2">
si vuota l'input, poiché il valore NON È UN NUMERO CORRETTO, ma una rappresentazione di stringa dipendente dalla locale.
Penso che il modo migliore per farlo sia quello di creare un filtro, in questo modo:
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
quindi il markup è simile al seguente:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Fiddle aggiornato: http://jsfiddle.net/BB4T4/
È una domanda pelosa a cui rispondere, perché non hai dato il contesto completo di ciò che stai facendo. La risposta accettata funzionerà, ma in alcuni casi causerà scarse prestazioni. Quello, e sarà più difficile testarlo.
Se lo stai facendo come parte di una forma statica, va bene. La risposta accettata funzionerà, anche se non è facile da testare ed è viziosa.
Ti consigliamo di mantenere qualsiasi "logica aziendale" (ovvero logica che altera i dati da visualizzare) fuori dalle tue viste. Questo è così che puoi testare l'unità della tua logica e quindi non finisci per accoppiare strettamente il tuo controller e la tua vista. Teoricamente, dovresti essere in grado di puntare il controller verso un'altra vista e utilizzare gli stessi valori degli ambiti. (se questo ha senso).
Dovresti anche considerare che qualsiasi chiamata di funzione all'interno di un binding (come {{}}
o ng-bind
o ng-bind-html
) dovrà essere valutata su ogni digest , perché angolare non ha modo di sapere se il valore è cambiato o no come sarebbe con una proprietà sul campo di applicazione.
Il modo "angolare" per farlo sarebbe quello di memorizzare nella cache il valore in una proprietà nell'ambito della modifica mediante un evento ng-change o persino un $ watch.
Ad esempio con un modulo statico:
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
dal momento che sembra funzionare solo con un piano Math.round()
?
Math
test. In alternativa, è possibile creare un servizio matematico e iniettarlo.
Perché non avvolgere l'intero oggetto matematico in 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]);
e usare:
{{number_var | matematica: 'ceil'}}
Se stai cercando di fare un semplice giro in Angolare, puoi facilmente impostare il filtro all'interno della tua espressione. Per esempio:
{{ val | number:0 }}
Vedi questo esempio di CodePen e per altre opzioni di filtro numerico.
Il modo più semplice per eseguire semplici calcoli con Angular è direttamente nel markup HTML per i singoli binding, se necessario, supponendo che non sia necessario eseguire calcoli di massa sulla pagina. Ecco un esempio:
{{(data.input/data.input2)| number}}
In questo caso, fai semplicemente i calcoli in () e poi usa un filtro | per ottenere una risposta numerica. Ecco ulteriori informazioni sulla formattazione di numeri angolari come testo:
Associare l'oggetto Math globale all'ambito (ricordarsi di usare $ window, non finestra)
$scope.abs = $window.Math.abs;
Usa l'associazione nel tuo HTML:
<p>Distance from zero: {{abs(distance)}}</p>
Oppure crea un filtro per la specifica funzione matematica che stai cercando:
module.filter('abs', ['$window', function($window) {
return function(n) {
return $window.Math.abs($window.parseInt(n));
};
});
Usa il filtro nel tuo HTML:
<p>Distance from zero: {{distance | abs}}</p>
Non sembra un modo molto angolare di farlo. Non sono del tutto sicuro del motivo per cui non funziona, ma probabilmente avrai bisogno di accedere all'ambito per utilizzare una funzione del genere.
Il mio consiglio sarebbe di creare un filtro. Questo è il modo angolare.
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
Quindi nel tuo HTML fai questo:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Il number
filtro formatta il numero con migliaia di separatori, quindi non è strettamente una funzione matematica.
Inoltre, il suo "limitatore" decimale non ha ceil
decimali tritati (come alcune altre risposte ti inducono a credere), ma piuttosto round
li ingigantisce.
Quindi, per qualsiasi funzione matematica che desideri, puoi iniettarla (più facile da deridere che iniettare l'intero oggetto Math) in questo modo:
myModule.filter('ceil', function () {
return Math.ceil;
});
Non è necessario avvolgerlo in un'altra funzione.
Questo è più o meno un riassunto di tre risposte (di Sara Inés Calderón, klaxon e Gothburz), ma poiché tutti hanno aggiunto qualcosa di importante, ritengo che valga la pena unire le soluzioni e aggiungere qualche spiegazione in più.
Considerando il tuo esempio, puoi fare calcoli nel tuo modello usando:
{{ 100 * (count/total) }}
Tuttavia, ciò può comportare un sacco di cifre decimali, quindi usare i filtri è un buon modo per andare:
{{ 100 * (count/total) | number }}
Per impostazione predefinita, il filtro numerico lascerà fino a tre cifre frazionarie , è qui che l' argomento fractionSize è abbastanza utile ( {{ 100 * (count/total) | number:fractionSize }}
), che nel tuo caso sarebbe:
{{ 100 * (count/total) | number:0 }}
Questo arrotonderà anche il risultato già:
L'ultima cosa da menzionare, se si fa affidamento su un'origine dati esterna, è probabilmente buona norma fornire un valore di fallback adeguato (altrimenti si potrebbe vedere NaN o nulla sul proprio sito):
{{ (100 * (count/total) | number:0) || 0 }}
Sidenote: a seconda delle specifiche, potresti anche essere in grado di essere più preciso con i tuoi fallback / definire già i fallback su livelli inferiori (ad es {{(100 * (count || 10)/ (total || 100) | number:2)}}
.). Tuttavia, questo potrebbe non avere sempre senso.
Esempio di dattiloscritto angolare usando una pipa.
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;
}
}
Aggiungi alle dichiarazioni @NgModule
@NgModule({
declarations: [
MathPipe,
quindi utilizzare nel modello in questo modo:
{{(100*count/total) | math:'round'}}
<p>The percentage is {{(100*count/total)| number:0}}%</p>
più nei commenti qui sotto.