Saad
Saad

Reputation: 1904

Update HTML when scope changes inside a service

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

Upvotes: 0

Views: 70

Answers (3)

Adrian
Adrian

Reputation: 8597

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.

Upvotes: 0

Anderson Andrade
Anderson Andrade

Reputation: 579

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});
        });
    }
}}]);

Upvotes: 0

Guillaume Georges
Guillaume Georges

Reputation: 4020

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;
                })
            }
        }
}]);

Upvotes: 1

Related Questions