1

I'm trying to update a view through a controller that sources its data from a service. For some reason, the view doesn't update when the service's data changes. I've distilled an example from my application here. I've tried all sorts of bindings ($scope.time = TimerService.value, wrapped in a function, using $watch - no success).

Note, in my original app, this is an array of objects and an object's attribute changes.

-- script.js --

var mod = angular.module('mymodule', []);

mod.service('TimerService', function() {
  this.value = 0;
  var self = this;
  setInterval(function() {
    self.value += 1;
  }, 2000)
});

mod.controller('TimerCtrl', ['TimerService', '$scope', function(TimerService, $scope) {
  $scope.time = TimerService.value;
  $scope.$watch(function() {
    return TimerService.value;
  }, function(newValue) {
    $scope.time = newValue;  
  }, true);
  $scope.otherValue = '12345';
}]);


angular.element(document).ready(function() {
  alert('start');
  angular.bootstrap(document, ['mymodule']);
});

-- index.html --

<!DOCTYPE html>
<html>

  <head>
    <script src="./angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>
      <div ng-controller="TimerCtrl">
          <h1>- {{ time }}-</h1>
          <h2>{{ otherValue }}</h2>
      </div>
  </body>

</html>
orange
  • 7,755
  • 14
  • 75
  • 139

3 Answers3

1

After spending some time with trial and error, I finally found the answer to the problem. In my example above (and my real application), the data gets changed outside of the angular scope (controller button click, http request, etc) which means a digest cycle is not getting kicked off. If I change the code to use $timeout(), it works. Unfortunately, this doesn't entirely solve my problem of the data being changed outside of angular (I guess I need to integrate the rest into angular as well).

Update

I managed to perform changes outside of angular by using rootscope in my service:

$rootscope.$apply(function() {
  // perform variable update here.
  self.value += 1;
});

This successfully propagates to the view.

orange
  • 7,755
  • 14
  • 75
  • 139
0

Try this

$scope.time = TimerService.value;
if(!$scope.$$phase) {
    $scope.$apply();
}
D.S
  • 1,110
  • 3
  • 11
  • 26
0

Try

var app = angular.module('myApp', []);
            var value = 0;
            var timer = setInterval('Repeater()', 1000);
            var Repeater = function () {
                value++;
                var scope = angular.element(document.getElementById('myApp')).scope();
                console.log(scope);
                scope.$apply(function () {
                        scope.time = value;
                    });
                };
            app.controller('TimerCtrl', ['$scope', function( $scope) {

          }]);

credit to https://stackoverflow.com/a/16520050/356380

Community
  • 1
  • 1
Whisher
  • 31,320
  • 32
  • 120
  • 201
  • Isn't the 2-way binding the beauty of Angular? Why would I need to deal with DOM elements in a service? In addition, the service may be used everywhere in the application, so I wouldn't know which part of the DOM is affected. – orange Oct 15 '13 at 21:51