23

A service with a 3rd party library callback function:

mbAppModule.service('aService', function ($http) {
    this.data={"somedata":0};
    var m3rdPartLib="init";  // init    
    m3rdPartLib.on('timeupdate', function() {
        this.data.somedata=1;
    });
}

And a controller

mbAppModule.controller({
    MController: function ($scope, $http, mService) {
        $scope.mService= mService;    
    });
});

html page

{{mService.data.somedata}}

PROBLEM :

m3rdPartLib.on() is a 3rd party library callback function which i am using it in a service. I want to show it in the ui as it is getting updated. On callback the value is getting changed, but not getting reflected on ui.

Read some docs and found $rootScope.$apply could be called, but i don't have the reference of $scope / $rootScope in the service.

4 Answers 4

30

You can take a dependency on $rootScope and call apply in your service.

mbAppModule.service('aService', ["$http", "$rootScope", function ($http, $rootScope) {
    this.data = {
        "somedata": 0
    };
    var m3rdPartLib = "init"; // init    
    m3rdPartLib.on('timeupdate', function () {
        $rootScope.$apply(function(){
            this.data.somedata = 1;
        });
    });
}]);
Sign up to request clarification or add additional context in comments.

1 Comment

jsfiddle I feel like it is better if the service should not need to know about the UI. To me it seems like that should fall onto the controller. This is easily done by creating a callback in your service to update the UI.
3

I needed to update an input field from a service because it had listeners and what not that changed data randomly and dynamically.

This could be used to call scope functions in the controller as well:

//scope will be set to current scope of a controller
//which has an ng-view containing this element    
var scope = angular.element('#input-element').scope();
//wrap changes in an apply call to make sure view and model are consistent
scope.$apply(function() {
    scope.object.data = value;
});

Thanks to this post: How do I access the $scope variable in browser's console using AngularJS?

Comments

0

Use $scope.$watch function. Look at my jsfiddle. I haven't your library, so I only simulate it - the value change from 0 to 1 after 5 seconds.

3 Comments

NAH ! this won't help. $timeout is part of angular so it will automatically call the apply and digest to update the scope.
Ok, so please check this jsfiddle.net/mchrobok/JE78Q/5. Does it work? I used events instead of watch.
@mchrobok Using a $watch isn't useful in this scenario. In your first fiddle, using service.data.somedata in the template reflect the change as well, without requiring a $watch. In your second, calling $rootScope.$apply() in the timeout function will trigger the change as well if you use service.data.somedata in the template without, one more time, having to use the event mechanism. As long as the reference is valid and a digest cycle is triggered, the value will be updated.
0

If you´re using scope in your service then it is a good indicator that you´re breaking SRP cause your service should only retrieve data to your controller. My suggestion is that you could do something like this.

mbAppModule.service('aService', ["$http", "$rootScope", function ($http, $rootScope) {
  this.data = {
    "somedata": 0
  };
  var m3rdPartLib = "init"; // init    
  this.GetPartLib = function () { 
    return m3rdPartLib;
  }
}]);

mbAppModule.controller({
  MController: function ($scope, $http, mService) {
  this.GetPartLib = function (){ 
    mService.on('timeupdate', function() {
     this.data.somedata=1;
    });
  }
});

1 Comment

This answer would benefit from some explanation. It may be obvious to some people what this is doing, but to others, especially beginners its not obvious at all.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.