Новое в Angular - Вычисляемые переменные
Я перехожу к Angular из нокаута, и у меня есть несколько вопросов. Я предполагаю, что я должен делать что-то типа не angular.
http://jsfiddle.net/LostInDaJungle/BxELP/
I linked to jsfiddle so I didn't have to include my code here
Qaru will not let me post my question without a code block.
Вот очень простая скрипка, в которой излагаются две основные проблемы...
Задача 1: val1 и val2 инициализируются как 3 и 4, и добавить до 7 правильно. Однако, если вы изменяете одно из значений в текстовых полях, новое значение рассматривается как строка, и я получаю конкатенацию вместо добавления. Измените val1 на 4, и вы получите 44, когда это должно быть 8. Каков наилучший способ для этого поведения?
Задача 2: Вычисленные поля. Я могу получить вычисленное поле, используя фигурные скобки, такие как {{val1 + val2}}, и автоматическое обновление вычисленных полей при изменении базовой модели, но это совершенно неприемлемо. В моем полнофункциональном приложении мы генерируем "стоимость", которая используется несколько раз повсюду, и каждый раз при необходимости вычислять затраты, это боль. Не говоря уже о том, что когда этот расчет меняется, у меня теперь есть незавидная задача найти 15 разных мест, которые используют калькуляцию затрат и обновляют их все.
Кроме того, если я попытаюсь поместить ng-model = "cost" на вкладке с фигурными скобками, то фигурные скобки не работают. Таким образом, ничто не выскакивает на меня как способ привязать стоимость.
http://jsfiddle.net/LostInDaJungle/QNVwe/
Этот пример больше похож на структуру, которую я желаю. Однако, в отличие от ko.observable, вычисленные поля не обновляются, когда изменяются значения, генерирующие их. Решение шаблона, на которое все навязывали мне, - написать кучу обработчиков ng-change... Но это ужасно. Если изменения ширины меняют стоимость и меняют расчеты окупаемости и т.д. Это быстро становится запутанным беспорядком.
Оба этих метода не позволяют отделить логику от представления. Первый метод имеет мою бизнес-логику, встроенную в мой HTML. Метод два ставит целую кучу обработчиков ng-change в моем коде, который не сильно отличается от того, чтобы писать весь беспорядок обработчиков onChange в plain ol 'HTML. Если мне нужно сделать кучу обработчиков изменений ng, я бы так же быстро обработал onChange в Javascript, потому что я могу хотя бы объявить их за пределами моего уровня представления.
Здесь версия для нокаута:
http://jsfiddle.net/LostInDaJungle/eka4S/2/
Это больше похоже на то, что я ожидал бы... Ничто, кроме привязки данных к моим входам, все программные логики прекрасно содержатся в модели представления. Кроме того, поскольку моя вычислимая функция Javascript, мне не нужно почесать голову о том, как обеспечить, чтобы мои два значения были числовыми.
Так....
Вычисленные переменные: есть ли способ посмотреть основные переменные и автоматически обновить вычисленную сумму? Без необходимости похоронить мою программную логику в моем HTML?
Есть ли хороший способ, чтобы мои числа не превращались в строки?
Благодарим вас за помощь.
FYI, также отправленный в группы Google: https://groups.google.com/forum/#!topic/angular/0dfnDTaj8tw
Ответы
Ответ 1
Для вычисленного поля добавьте метод к вашему контроллеру.,.
$scope.cost = function() { return $scope.val1 + $scope.val2 };
а затем привязать его напрямую. Он будет знать, когда он должен пересчитываться по мере изменения его составляющих значений.
<div>{{cost()}}</div>
Ответ 2
Хорошо,
Несколько часов спустя, и я думаю, что у меня есть мой ответ.
Использование $scope. $watch.
$scope.$watch('(height * width) * 40', function(v) {$scope.cost = v;});
или
$scope.$watch('height + width', function() {$scope.cost = (Number(height) * Number(width)) * 40;});
Это автоматическое обновление любых вычислений для наблюдаемых переменных. И это дает мне способ работать с ними без необходимости жить внутри фигурных скобок.
Кроме того, вычисленные значения можно повторно использовать и отслеживать для каскадных обновлений:
$scope.$watch('height * width', function(v) {$scope.dim = v;});
$scope.$watch('dim * 40', function(v) {$scope.cost = v;});
Поэтому, если высота и/или ширина изменяются, dim обновляется, а так как dim изменен, стоимость обновляется.
Ответ 3
Я изменил свой третий вход на:
<input type="text" value="{{val1 * 1 + val2}}" />
который вызывает Angular.js для обработки значений как чисел, а не строк.
Вот fiddle. Я почерпнул ответ из здесь.
Ответ 4
О проблеме 1:
Если возможно, следует использовать тип ввода = "номер". Это правильно позаботится о разборе чисел. Даже если у вас более старый браузер angular, он позаботится о форматировании их как чисел.
О проблеме 2:
Ваш ответ хороший Джейсон, если вам просто нужно показать простой текст на экране. Однако, если вы хотите привязать вход с моделью к произвольному выражению, вам нужно что-то еще.
Я написал директиву, которую вы можете использовать для привязки ng-модели к любому выражению, которое вы хотите. Всякий раз, когда выражение изменяется, модель устанавливается в новое значение.
module.directive('boundModel', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
scope.$watch(attrs.boundModel, function(newValue, oldValue) {
if(newValue != oldValue) {
ngModel.$setViewValue(newValue);
ngModel.$render();
}
});
}
};
})
Вы можете использовать его в своих шаблонах, например:
<input type="text" ng-model="total" bound-model="value1 + value2">
Или вот так:
<input type="text" ng-model="total" bound-model="cost()">
Где cost() - простая функция области, подобной этой:
$scope.cost = function() { return $scope.val1 + $scope.val2 };
Хорошо, что вы продолжаете использовать модель для ввода, и вам не нужно динамически обновлять свой атрибут value, что не работает в angular.
Ответ 5
Я новичок в AngularJS, но думаю, что можно использовать $parse:
http://docs.angularjs.org/api/ng/service/ $parse
Это интересно, если у вас есть выражение в виде строки. Вы можете использовать путь к свойствам и эту строку можно генерировать динамически. Это работает, если вы не знаете выражение во время компиляции, как eval(), но, вероятно, намного быстрее и, возможно, более безопасным (?).
Вот пример:
function Ctrl($scope,$parse) {
var expression = 'model.val1 + model.val2';//could be dynamically created
$scope.model = {
val1: 0,
val2: 0,
total: function() {
return ($parse(expression))($scope);
}
};
}
Ответ 6
u может связываться с функцией
function CTRL ($scope) {
$scope.val1 = 3;
$scope.val2 = 4;
$scope.sum = function(){
return ($scope.val1 *1 + $scope.val2 *1);
};
}
он будет работать одинаково
выражение привязки будет работать, но в гораздо более сложных случаях нам нужны функции
Ответ 7
Функция $watch, которая доступна через переменную $scope, лучше всего подходит для этой работы, на мой взгляд.
$scope.$watch(function(scope) { return scope.data.myVar },
function(newValue, oldValue) {
document.getElementById("myElement").innerHTML =
"" + newValue + "";
}
);
Функция $watch принимает:
функция значения
& Амп; функция слушателя
Приведенный выше пример взят из этой удивительной статьи: http://tutorials.jenkov.com/angularjs/watch-digest-apply.html
Прочитав это, я многому научился и смог реализовать решение, которое я искал.