0

I have an html element which I would like to update upon different actions.

HTML

<span>{{progress.mandates_transferred}}/{{progress.mandates_count}}</span>

js

    this.app.controller('appController', ['MandateService', function(MandateService){
    MandateService.progress($scope)

    $scope.MarkDone = function() {
      MandateService.progress($scope)
    }

}])
   this.app.service('MandateService' [
    '$http',
    function($http) {
      var url = 'api/mandate'
      return {
        progress: function($scope) {
             $http.get(url).success(function(data) {
             $scope.progress = data
        })
                  }
      }}])

There is a click action markDone which calls the MandateService to update the $scope values

the value $scope.progress updates if I add a console.log in the service to check the values in $scope but it is not updated in the HTML. I have tried a few techniques mentioned but none of them help

I have tried adding $scope.$apply() but I get an error $digest already in progress sol1 sol2

Saad
  • 1,856
  • 1
  • 22
  • 28

3 Answers3

1

You should not be accessing $scope inside a service, but rather have your service function return data that you will update your $scope with, in your controller.

this.app.controller('appController', ['MandateService', function(MandateService) {

    $scope.MarkDone = function() {
        $scope.progress = MandateService.progress();
    }

}]);


this.app.service('MandateService' ['$http', function($http) {
        var url = 'api/mandate'
        return {
            progress: function() {
                $http.get(url).success(function(data) {
                    return data;
                })
            }
        }
}]);
Guillaume Georges
  • 3,878
  • 3
  • 14
  • 32
0

You can use $broadcast, try this:

this.app.controller('appController', ['$scope', '$rootScope','MandateService', function($scope, $rootScope, MandateService){
    MandateService.progress($scope)

    $scope.MarkDone = function() {
      MandateService.progress($scope)
    }

    $rootScope.$on('progress_update', function(event, data){
      $scope.progress = data.progress;
    });

}])

this.app.service('MandateService' ['$http', '$rootScope', function($http, $rootScope) {
  var url = 'api/mandate'
  return {
    progress: function() {
         $http.get(url).success(function(data) {
            $rootScope.$broadcast('progress_update', {progress: data});
        });
    }
}}]);
Anderson Andrade
  • 569
  • 1
  • 4
  • 13
0

While the other answers are correct and will achieve the same end result, I would suggest using callbacks within services, might be my personal habit, but it makes the code much cleaner in my opinion (Of course if you don't make spaghetti out of it and end up in thousands of callbacks, then your code will be unreadable).

this.app.controller('appController', ['MandateService', function(MandateService)   {  

    $scope.progress = {};

    $scope.MarkDone = function() {  
         MandateService.progress(function(data){
            $scope.progress = data;
         })
    }

}]) 

this.app.service('MandateService'['$http', function($http)   {  
   var url = 'api/mandate' 
   return {  
      progress:function(callback) {  
         $http.get(url).success(function(data) {  
           callback(data);
         })
      }
   }
}])

A callback in a service.. you pass a function which will be called once the $http.get completes and returns variable data back to the calling function. Simple & Effective.

Adrian
  • 8,271
  • 2
  • 26
  • 43
  • I have tried this but it does not really updates the HTML, although the new values are in the scope – Saad Oct 20 '17 at 14:45
  • @Saad First define the scope variable before you assign the value (See my edit). – Adrian Oct 20 '17 at 14:48
  • I tried that and I am getting this error Error: [$rootScope:inprog] $digest already in progress – Saad Oct 20 '17 at 14:49
  • @Saad That's correct. I edited my comment and answer. – Adrian Oct 20 '17 at 14:50
  • I have tried that but inside the MandateService.progress(function(data){ $scope.progress = data; console.log($scope.progress) }) the value is correct but outside the value of $scope.progress still does not change – Saad Oct 20 '17 at 14:57
  • Did you define the $scope.progress = {}; outside the function? What data is your request returning? – Adrian Oct 20 '17 at 15:00
  • Yes I did define the scope and it is returning a JS object. – Saad Oct 23 '17 at 07:45