Reputation: 282
I am writing a simple controller which does few calculations. This is a reflection of a real project with more advanced information. The problem is that the result, when placed on the html as an expression is being recalcualted with every change, however, when I am calculating in the $scope as a variable, it does not update. see comment in the the markup.
Any idea what I am missing here?
markup
<body ng-app="myApp">
<div ng-controller="mainController">
<h3> Numbers </h3>
<label> a </label>
<input type="number" ng-model="numbers.a"/>
<label> b </label>
<input type="number" ng-model="numbers.b">
<br>
<br>
<span> Result : {{result}} {{numbers.a*numbers.b}} </span> // the first one does not update, but the second does.
<h3> Nums </h3>
<label> a </label>
<input type="number" ng-model="a1">
<label> b</label>
<input type="number" ng-model="b1">
<br>
Result2: {{result2}} {{a1+b1}}
<ul>
<li ng-repeat=" i in cool"> {{i}} </li>
</ul>
</div>
</body>
javascript:
angular.module('myApp',[])
.controller('mainController', ['$scope', function($scope) {
$scope.numbers = {a:11, b:10};
$scope.a1 = 5;
$scope.b1 = 7;
$scope.result = $scope.numbers.a*$scope.numbers.b;
$scope.result2 = $scope.a1 +$scope.b1 ;
$scope.cool = [$scope.result + $scope.result2,
$scope.result - $scope.result2]
}]);
http://codepen.io/Tallyb/pen/rVdebm
Upvotes: 0
Views: 126
Reputation: 166
The first variable result
doesn't update, because your mainController
function only gets evaluated once - which is the first time angular interprets the html and first discovers the expression ng-controller="mainController"
.
In order to get result
to update automatically, you have to set up watch listeners in the controller like this:
angular.module('myApp',[])
.controller('mainController', ['$scope', function($scope) {
// ...
$scope.$watch('[numbers.a, numbers.b]', function () {
$scope.result = $scope.numbers.a*$scope.numbers.b;
});
}]);
An expression like {{numbers.a*numbers.b}}
will update automatically, because angular will set up watch listeners for those. In fact, the expression syntax in the html is just syntactic sugar - under the hood, angular just invokes the same $watch
functions for every expression it finds in the html.
See the $watch documentation for more detail.
I personally prefer not to use the $watch
syntax mentioned above, because it bloats the controller. Alternatively, you can call a function from your html:
{{ calculateResult() }}
In your controller, you would then define the function like this:
angular.module('myApp',[])
.controller('mainController', ['$scope', function($scope) {
// ...
$scope.calculateResult = function () {
return $scope.numbers.a*$scope.numbers.b;
};
}]);
Side note: If you're concerned about performance and your calculateResult()
function is really slow, you might want to stick to the first version though.
Upvotes: 2
Reputation: 388436
You need a watch to recalculate the value of result when the numbers is changed. Otherwise the value of result
is calculated only once
var app = angular.module('my-app', [], function() {})
app.controller('mainController', ['$scope',
function($scope) {
$scope.numbers = {
a: 11,
b: 10
};
$scope.a1 = 5;
$scope.b1 = 7;
//if a or b is changed recalculate result
$scope.$watch('[numbers.a, numbers.b]', function() {
$scope.result = $scope.numbers.a * $scope.numbers.b;
})
//if a1 or b1 is changed recalculate result2
$scope.$watch('[a1, b1]', function() {
$scope.result2 = $scope.a1 + $scope.b1;
})
//if result or result2 is changed recalculate cool
$scope.$watch('[result, result2]', function() {
$scope.cool = [$scope.result + $scope.result2,
$scope.result - $scope.result2
]
})
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="my-app">
<div ng-controller="mainController">
<h3> Numbers </h3>
<label>a</label>
<input type="number" ng-model="numbers.a" />
<label>b</label>
<input type="number" ng-model="numbers.b" />
<br/>
<br/>
<span> Result : {{result}} {{numbers.a*numbers.b}} </span> // the first one does not update, but the second does.
<h3> Nums </h3>
<label>a</label>
<input type="number" ng-model="a1" />
<label>b</label>
<input type="number" ng-model="b1" />
<br/>Result2: {{result2}} {{a1+b1}}
<ul>
<li ng-repeat=" i in cool">{{i}}</li>
</ul>
</div>
</div>
Upvotes: 0
Reputation: 2170
The calculations in the controller are only executed when the controller is instantiated, typically when the corresponding view is displayed. You'll have to encapsulate the calculation in functions (no $watch necessary):
$scope.result = function() {
return $scope.numbers.a * $scope.numbers.b;
}
$scope.result2 = function() {
return $scope.a1 + $scope.b1;
}
$scope.cool = function() {
return [
$scope.result() + $scope.result2(),
$scope.result() - $scope.result2()
];
}
and reference it in your view:
<span> Result : {{result()}} {{numbers.a*numbers.b}} </span>
and:
Result2: {{result2()}} {{a1+b1}}
and:
<li ng-repeat=" i in cool(result, result2)"> {{i}} </li>
see: http://codepen.io/anon/pen/vORXpg
Upvotes: 1