I have Angular application made of following tiers:
service()
used for computations and data-mungingfactory()
used as common data storage for multiple controllerscontrollers()
My controller exposes function from factory that, in turn, calls function from service. In HTML, I run controller function and display output to user: {{ controller.function() }}
.
I have noticed that when page is loaded, and on every subsequent model change, controller.function()
is run twice. Why does it happen? How can I avoid unnecessary invocation?
See working example - open your browser JS console, click Run
and observe that console.log()
line is executed two times.
angular.module('myApp',[])
.service('Worker', [function() {
this.i = 0;
this.sample = function(data) {
console.log(this.i.toString() + " " + Math.random().toString());
return JSON.stringify(data);
};
}])
.factory('DataStorage', ['Worker', function(worker) {
var self = this;
self.data = [{}, {}];
self.getData = function() {
return self.data;
}
self.sample = function() {
return worker.sample(self.data);
};
return {
getData: self.getData,
sample: self.sample
};
}])
.controller('MainController', ['DataStorage', function(DataStorage) {
var self = this;
self.data = DataStorage.getData();
self.sample = DataStorage.sample;
}])
.controller('DataSource', [function() {
var self = this;
self.data = ["one", "two", "three", "four", "five", "six"];
}])
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script data-require="[email protected]" data-semver="1.5.8" src="https://opensource.keycdn.com/angularjs/1.5.8/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="MainController as main">
<div ng-controller="DataSource as datasource">
<div ng-repeat="select in main.data">
<select ng-model="select.choice" ng-options="value for value in datasource.data">
<option value="">-- Your choice --</option>
</select>
</div>
<pre>
{{ main.sample() }}
</pre>
</div>
</body>
</html>
Why does this function run multiple times for every single model change and how can I ensure that it runs only once?
I have tried assigning factory function output to controller variable (and use {{ controller.function }}
in HTML - note lack of parentheses), but then function is run only once ever. It should run on new data when model is changed.
Similar problems reported on StackOverflow all refer to ng-route module, which I am not using.
This is happened because you are calling function sample()
in expression like this:
{{ main.sample() }}
This function will be called at least twice if you use expression like that.
Reason is because Angular runs digest cycle until everything is up to date (So, it will be at least twice). In your case it run first time to return value and second time to verify are there any changes left.
You can ensure that it runs only once if you place your function in ng-change
directive instead.
In your case it will be:
<select ng-model="select.choice" ng-change="main.sample()" ng-options="value for value in datasource.data">
<option value="">-- Your choice --</option>
</select>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With