Czy istnieje sposób używania funkcji matematycznych w powiązaniach AngularJS?
na przykład
<p>The percentage is {{Math.round(100*count/total)}}%</p>
To skrzypce pokazuje problem
private Math = Math;
i możesz go użyć.
Czy istnieje sposób używania funkcji matematycznych w powiązaniach AngularJS?
na przykład
<p>The percentage is {{Math.round(100*count/total)}}%</p>
To skrzypce pokazuje problem
private Math = Math;
i możesz go użyć.
Odpowiedzi:
Musisz wstrzyknąć Math
do swojego zakresu, jeśli musisz go użyć, ponieważ
$scope
nic nie wiesz o matematyce.
Najprościej możesz to zrobić
$scope.Math = window.Math;
w twoim kontrolerze. Myślę, że dobrym sposobem na zrobienie tego poprawnie byłoby stworzenie usługi matematycznej.
formatting
, więc użyj filtru.
Chociaż przyjęta odpowiedź jest słuszna, że można wstrzyknąć, Math
aby użyć jej w kanale kątowym, w przypadku tego konkretnego problemu bardziej konwencjonalny / kątowy jest filtr liczb:
<p>The percentage is {{(100*count/total)| number:0}}%</p>
Możesz przeczytać więcej o number
filtrze tutaj: http://docs.angularjs.org/api/ng/filter/number
{{1234.567|number:2}}
renderuje jako 1,234.57
lub 1 234,57
. Jeśli spróbujesz przekazać to <input type="number" ng-value="1234.567|number:2">
, puste dane wejściowe, ponieważ NIE JEST PRAWIDŁOWA LICZBA, ale zależna od ustawień regionalnych reprezentacja ciągu.
Myślę, że najlepszym sposobem na to jest utworzenie filtra, takiego jak ten:
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
znaczniki wyglądają następująco:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Zaktualizowano skrzypce: http://jsfiddle.net/BB4T4/
Jest to owłosiona odpowiedź, ponieważ nie podałeś pełnego kontekstu tego, co robisz. Przyjęta odpowiedź będzie działać, ale w niektórych przypadkach spowoduje niską wydajność. To będzie trudniejsze do przetestowania.
Jeśli robisz to jako część statycznej formy, dobrze. Zaakceptowana odpowiedź zadziała, nawet jeśli nie jest to łatwe do przetestowania, i jest pokręcona.
Będziesz chciał ukryć jakąkolwiek „logikę biznesową” (tj. Logikę, która zmienia dane, które mają być wyświetlane) z dala od twoich widoków. Jest to możliwe, abyś mógł przetestować logikę jednostkową, aby nie skończyć ściśle połączeniem kontrolera i widoku. Teoretycznie powinieneś być w stanie skierować kontroler na inny widok i używać tych samych wartości z zakresów. (Jeśli to ma sens).
Należy również wziąć pod uwagę, że wszelkie wywołania funkcji w powiązaniu (takie jak {{}}
lub ng-bind
lub ng-bind-html
) będą musiały być oceniane przy każdym skrócie , ponieważ kątowy nie ma możliwości dowiedzenia się, czy wartość się zmieniła, czy nie, jak w przypadku właściwości w zakresie.
„Kątowym” sposobem na wykonanie tego byłoby buforowanie wartości we właściwości w zakresie przy zmianie za pomocą zdarzenia ng-change lub nawet $ watch.
Na przykład w formie statycznej:
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
po co dalej, skoro wydaje się, że działa to z właściwym planem Math.round()
?
Math
testów. Alternatywnie możesz utworzyć usługę matematyczną i wstrzyknąć ją.
Dlaczego nie owinąć całego obiektu matematyki w filtr?
var app = angular.module('fMathFilters',[]);
function math() {
return function(input,arg) {
if(input) {
return Math[arg](input);
}
return 0;
}
}
return app.filter('math',[math]);
i użyć:
{{number_var | matematyka: „ceil”}}
Jeśli chcesz zrobić prostą rundę w Angular, możesz łatwo ustawić filtr w swoim wyrażeniu. Na przykład:
{{ val | number:0 }}
Zobacz przykład CodePen i inne opcje filtrowania liczb.
Najprostszym sposobem na wykonanie prostej matematyki za pomocą Angulara jest użycie znaczników HTML dla poszczególnych powiązań w razie potrzeby, zakładając, że nie musisz wykonywać obliczeń masy na swojej stronie. Oto przykład:
{{(data.input/data.input2)| number}}
W takim przypadku wystarczy wykonać obliczenia matematyczne w (), a następnie użyć filtru | aby uzyskać odpowiedź liczbową. Oto więcej informacji na temat formatowania liczb kątowych jako tekstu:
Powiąż globalny obiekt Math z zasięgiem (pamiętaj, aby użyć $ window nie window)
$scope.abs = $window.Math.abs;
Użyj powiązania w swoim HTML:
<p>Distance from zero: {{abs(distance)}}</p>
Lub utwórz filtr dla określonej funkcji matematycznej, której szukasz:
module.filter('abs', ['$window', function($window) {
return function(n) {
return $window.Math.abs($window.parseInt(n));
};
});
Użyj filtra w swoim HTML:
<p>Distance from zero: {{distance | abs}}</p>
To nie wygląda na bardzo Angularny sposób. Nie jestem do końca pewien, dlaczego to nie działa, ale prawdopodobnie potrzebujesz dostępu do zakresu, aby użyć takiej funkcji.
Moją sugestią byłoby utworzenie filtra. To jest sposób Angularny.
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
Następnie w swoim HTML zrób to:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
number
Filtr formatuje numer z tysiącami separatorów, więc nie jest to ściśle funkcją matematyki.
Co więcej, jego dziesiętny „ogranicznik” nie ma ceil
żadnych posiekanych miejsc po przecinku (jak w niektórych innych odpowiedziach można by w to uwierzyć), a raczej round
ich odmierzanie.
Tak więc dla dowolnej funkcji matematycznej możesz ją wstrzyknąć (łatwiej kpić niż wstrzyknąć cały obiekt Math) w następujący sposób:
myModule.filter('ceil', function () {
return Math.ceil;
});
Nie trzeba też owijać go w inną funkcję.
To mniej więcej podsumowanie trzech odpowiedzi (Sary Inés Calderón, Klaxona i Gothburza), ale ponieważ wszystkie one dodały coś ważnego, uważam, że warto przyłączyć się do rozwiązań i dodać więcej wyjaśnień.
Biorąc pod uwagę twój przykład, możesz wykonać obliczenia w swoim szablonie, używając:
{{ 100 * (count/total) }}
Może to jednak skutkować dużą liczbą miejsc po przecinku, dlatego dobrym rozwiązaniem jest użycie filtrów :
{{ 100 * (count/total) | number }}
Domyślnie filtr liczb pozostawia do trzech cyfr ułamkowych , w tym przypadku argument fractionSize jest bardzo przydatny ( {{ 100 * (count/total) | number:fractionSize }}
), co w twoim przypadku byłoby:
{{ 100 * (count/total) | number:0 }}
Zaokrągli to również wynik:
Ostatnią rzeczą do wspomnienia, jeśli korzystasz z zewnętrznego źródła danych, prawdopodobnie dobrą praktyką jest zapewnienie właściwej wartości zastępczej (w przeciwnym razie możesz zobaczyć NaN lub nic na swojej stronie):
{{ (100 * (count/total) | number:0) || 0 }}
Sidenote: W zależności od specyfikacji możesz być w stanie być bardziej precyzyjnym dzięki swoim awariom / definiować już awarie na niższych poziomach (np {{(100 * (count || 10)/ (total || 100) | number:2)}}
.). Chociaż nie zawsze może to mieć sens.
Przykład Anges Typescript przy użyciu potoku.
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;
}
}
Dodaj do deklaracji @NgModule
@NgModule({
declarations: [
MathPipe,
następnie użyj w swoim szablonie tak:
{{(100*count/total) | math:'round'}}
<p>The percentage is {{(100*count/total)| number:0}}%</p>
więcej w komentarzu poniżej.