Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS service http success function using wrong "this" scope

The success function of a $http.put doesn't have access to the this scope of the service it's being called inside. I need to update a property of the service in the call back from the PUT request.

This is a cut down example of what I'm trying to do in a service:

var myApp = angular.module('myApp', function($routeProvider) {
// route provider stuff
}).service('CatalogueService', function($rootScope, $http) {
    // create an array as part of my catalogue
    this.items = [];

    // make a call to get some data for the catalogue
    this.add = function(id) {
        $http.put(
            $rootScope.apiURL,
            {id:id}
        ).success(function(data,status,headers,config) {
             // on success push the data to the catalogue
             // when I try to access "this" - it treats it as the window
             this.items.push(data);
        }).success(function(data,status,headers,config) {
            alert(data);
        });
    }
}

Sorry if there are some errors in the JS, the main point is how do I access the service scope from inside the success callback?

EDIT : while the answer to this question was correct, I switched to the factory method as both Josh and Mark recommended it

like image 483
Pete Avatar asked Feb 15 '13 23:02

Pete


2 Answers

As far as I know, you can't. But I wouldn't try to run the service that way anyway. Here is a cleaner way:

.factory('CatalogueService', function($rootScope, $http) {
  // We first define a private API for our service.

  // Private vars.
  var items = [];

  // Private methods.
  function add( id ) {
    $http.put( $rootScope.apiURL, {id:id} )
    .success(function(data,status,headers,config) { items.push(data); })
    .then(function(response) { console.log(response.data); });
  }

  function store( obj ) {
    // do stuff
  }

  function remove( obj ) {
    // do stuff
  }

  // We now return a public API for our service.
  return {
    add: add,
    store: store,
    rm: remove
  };
};

This is a very common pattern of developing services in AngularJS and it doesn't require any use of this in these cases.

like image 183
Josh David Miller Avatar answered Nov 16 '22 01:11

Josh David Miller


Create a closure over a variable (often called that) that is assigned to this so that your callback functions will have access to your service object:

app.service('CatalogueService', function($rootScope, $http) {
    var that = this;
    ...
        ).success(function(data,status,headers,config) {
          that.items.push(data);

Here is a Plunker that uses $timeout instead of $http to demonstrate.

like image 38
Mark Rajcok Avatar answered Nov 16 '22 02:11

Mark Rajcok