Есть ли способ использовать математические функции в привязках AngularJS?
например.
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Эта скрипта показывает проблему
Есть ли способ использовать математические функции в привязках AngularJS?
например.
<p>The percentage is {{Math.round(100*count/total)}}%</p>
Эта скрипта показывает проблему
Вам нужно ввести Math
в свою область действия, если вам нужно использовать ее как
$scope
ничего не знает о математике.
Простейший способ, вы можете сделать
$scope.Math = window.Math;
в вашем контроллере. Angular, чтобы сделать это правильно, я создаю Math-сервис.
В то время как принятый ответ прав, что вы можете ввести Math
, чтобы использовать его в angular, для этой конкретной проблемы более обычным способом /angular является числовой фильтр:
<p>The percentage is {{(100*count/total)| number:0}}%</p>
Подробнее о фильтре number
вы можете прочитать здесь: http://docs.angularjs.org/api/ng/filter/number
Я думаю, что лучший способ сделать это - создать фильтр, например:
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
тогда разметка выглядит следующим образом:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Обновлен скрипт: http://jsfiddle.net/BB4T4/
Это волосатый ответ, потому что вы не дали полного контекста того, что вы делаете. Принятый ответ будет работать, но в некоторых случаях это приведет к низкой производительности. Это, и это будет труднее проверить.
Если вы делаете это как часть статической формы, отлично. Принятый ответ будет работать, даже если его нелегко проверить, и это неловко.
Вы хотите сохранить любую "бизнес-логику" (то есть логику, которая изменяет отображаемые данные) из ваших представлений. Это значит, что вы можете unit test использовать свою логику, и поэтому вы не будете плотно связывать ваш контроллер и ваше представление. Теоретически, вы должны указывать ваш контроллер на другое представление и использовать те же значения из областей. (если это имеет смысл).
Вы также захотите рассмотреть, что любые вызовы функций внутри привязки (например, {{}}
или ng-bind
или ng-bind-html
) должны оцениваться на каждом дайджесте, потому что angular не имеет способа зная, изменилось ли значение или не понравилось это с свойством в области видимости.
"Angular" способ сделать это будет кэшировать значение в свойстве в области смены при изменении с помощью события ng change или даже $watch.
Например, со статической формой:
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.
});
});
Лучше использовать:
{{(100*score/questionCounter) || 0 | number:0}}
Он устанавливает значение по умолчанию для уравнения равным 0 в случае, когда значения не инициализируются.
Самый простой способ сделать простую математику с помощью Angular - это непосредственно в разметке HTML для отдельных привязок по мере необходимости, предполагая, что вам не нужно делать массовые вычисления на своей странице. Вот пример:
{{(data.input/data.input2)| number}}
В этом случае вы просто выполните математику в(), а затем используйте фильтр | чтобы получить номер ответа. Здесь больше информации о форматировании чисел Angular в виде текста:
Если вы хотите сделать простой раунд в Angular, вы можете легко установить фильтр внутри своего выражения. Например:
{{ val | number:0 }}
Смотрите этот CodePen пример и для других параметров фильтра числа.
Почему бы не обернуть всю математику obj в фильтре?
var app = angular.module('fMathFilters',[]);
function math() {
return function(input,arg) {
if(input) {
return Math[arg](input);
}
return 0;
}
}
return app.filter('math',[math]);
и использовать:
{{number_var | математика: 'CEIL'}}
Либо привязать глобальный объект Math к области (не забудьте использовать $window not window)
$scope.abs = $window.Math.abs;
Используйте привязку в своем HTML:
<p>Distance from zero: {{abs(distance)}}</p>
Или создайте фильтр для конкретной математической функции, которую вы выполняете:
module.filter('abs', ['$window', function($window) {
return function(n) {
return $window.Math.abs($window.parseInt(n));
};
});
Используйте фильтр в своем HTML:
<p>Distance from zero: {{distance | abs}}</p>
Это не похоже на способ Angular сделать это. Я не совсем уверен, почему он не работает, но вам, вероятно, потребуется получить доступ к области, чтобы использовать такую функцию.
Мое предложение было бы создать фильтр. Это способ Angular.
myModule.filter('ceil', function() {
return function(input) {
return Math.ceil(input);
};
});
Затем в вашем HTML сделайте следующее:
<p>The percentage is {{ (100*count/total) | ceil }}%</p>
Это более или менее резюме трех ответов (Sara Inés Calderón, klaxon и Gothburz), но поскольку все они добавили что-то важное, я считаю целесообразным присоединиться к решениям и добавить еще несколько объяснений.
Учитывая ваш пример, вы можете делать вычисления в своем шаблоне, используя:
{{ 100 * (count/total) }}
Однако это может привести к большому количеству десятичных знаков, поэтому с использованием фильтров является хорошим способом:
{{ 100 * (count/total) | number }}
По умолчанию фильтр количества будет оставить до трех дробных цифр, здесь находится аргумент fractionSize очень удобно
({{ 100 * (count/total) | number:fractionSize }}
), что в вашем случае будет:
{{ 100 * (count/total) | number:0 }}
Это также будет округлять результат:
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>
Фильтр number
форматирует число с разделителями тысяч, поэтому это не строго математическая функция.
Кроме того, его десятичный "лимитер" не ceil
не нарезал десятичные числа (как некоторые другие ответы заставляют вас поверить), а скорее round
их.
Итак, для любой математической функции, которую вы хотите, вы можете ввести ее (проще обмануть, чем впрыснуть весь объект Math) следующим образом:
myModule.filter('ceil', function () {
return Math.ceil;
});
Не нужно также обертывать его другой функцией.