Reputation: 97
I'm trying to create a simple example with 2 controllers and 2 services, where one of the services is called every 3 seconds.
A controller1 calls a service, which changes a value used in a controller2. I pass the value throught another service, but the value is not updated on my html page, only after I press 'Stop' button of my example (in bellow).
Can I update page value on every poll?
<html ng-app="myApp">
<head>
<title>MyApp</title>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp',[]);
app.service('SimpleService', function() {
var _value = 0;
var setValue = function(v) {
_value = v;
}
var getValue = function(){
return _value;
}
return {
setValue: setValue,
getValue: getValue
};
})
app.service('PollService', function(SimpleService) {
var poll = undefined;
var startPolling = function(){
poll = setInterval(function(){
console.info('poll...');
console.info(SimpleService.getValue());
SimpleService.setValue(SimpleService.getValue()+1);
}, 3000);
}
var stopPolling = function(){
clearInterval(poll);
}
return {
startPolling: startPolling,
stopPolling: stopPolling
};
})
app.controller('Controller1',function($scope, PollService){
var poll = undefined;
$scope.startPolling = function(){
PollService.startPolling();
}
$scope.stopPolling = function(){
console.info('stop');
PollService.stopPolling();
}
});
app.controller('Controller2', function($scope, SimpleService){
$scope.newVal = function(){
return SimpleService.getValue();
}
});
</script>
</head>
<body>
<div ng-controller="Controller1">
<button ng-click="startPolling()">Start</button>
<button ng-click="stopPolling()">Stop</button>
<br/>
<br/>
</div>
<div ng-controller="Controller2">
<h5>New value: {{newVal()}}</h5>
</div>
</body>
Regards.
Upvotes: 0
Views: 125
Reputation: 1449
Since setInterval is not an angular function, angular doesn't know that the value is updated and can't tell the DOM that the value is dirty, and therefore is not updated.
If you want to continue using setInterval
instead of angular's $interval, you can inject $rootScope
into your polling service, and then you can use $rootScope.$apply
to digest the value which will update the DOM. You can do
$rootScope.$apply(function(){
SimpleService.setValue(SimpleService.getValue()+1);
});
inside your setInterval
function.
Otherwise, $interval
is an angular.js wrapper for the setInterval
function, which does not require manually calling $apply.
I made changes to your code and some examples for how you might be able to better structure your use of service in controller scope.
Mainly, since a service is an object, we can directly reference the service's context in the DOM by adding the service itself to the controller scope, rather than reference's to the individual object keys. This eliminates the need to call a getter function from the DOM (as you do when you call {{newValue()}} ).
Upvotes: 1
Reputation: 2480
You need to invoke the digest cycle each time you're invoking the setter in the SimpleService. The view bindings will not update unless a fresh digest cycle starts. Here is the working code snippet.
app.service('SimpleService', function($rootScope) {
var _value = 0;
var setValue = function(v) {
_value = v;
$rootScope.$apply(); //added this here
}
var getValue = function(){
return _value;
}
return {
setValue: setValue,
getValue: getValue
};
})
You need to do scope.apply(). $apply evaluates any expressions in your template and starts a new digest cycle.In the $digest phase the scope examines all of the $watch expressions and compares them with the previous value. You can checkout the documentation about it here.
Some other issues I noticed in your code:
app.controller('Controller2', function($scope, SimpleService2){
$scope.newVal = function(){
return SimpleService.getValue();
}
});
Here, correct the name to SimpleService.
There is no method for stopPropagation.I added it as follows in the PollService to get your code working:
var stopPolling = function(){
clearInterval(poll);
}
Upvotes: 3