79

I have an AngularJS service defined in the following way

angular.module('myService').service('myService', function() {
  this.publicFunction(param) {
    ...
  };

  this.anotherPublicFunction(param) {
    // how to call publicFunction(param)?
    ...
  };
});    

and I would like to call the first function both from outside the service (which works fine by myService.publicFunction(xxx)) and from another function in the same service, i.e. anotherPublicFunction. Neither one of this.publicFunction(param) or myService.publicFunction(param) won't work from within the second function, and I can understand that.


EDIT:
Actually the whole problem was caused by something you can't reproduce with my example alone. I passed the second function as a callback parameter to another function in a separate controller, and when it is called, the reference to this doesn't work.

E.g.

anotherService.someCall('a', 123, myService.anotherPublicFunction);

fails inside anotherPublicFunction because this can't be resolved.

I've written a Plunker to show the problem: http://plnkr.co/edit/rrRs9xnZTNInDVdapiqF?p=info

(I'll still leave the question here in case it will help someone else.)


I know I could get around the problem by using a reference to the service or the first function like this

var ms = this;
this.anotherPublicFunction(param) {
  ms.publicFunction(param);
  ...
};

or this

var pf = this.publicFunction;
this.anotherPublicFunction(param) {
  pf(param);
  ...
};

but both seem like dirty hacks.

Is there a good way to call the first function from the second one in this case? Or am I doing something totally wrong in the first place to have a service like this?

I found these questions with good answers:

but they differ from my problem since one of them has a separate, internal function that was to be called, and the other one was using a factory instead of a service.

EDIT:

After posting this I immediately realized I could also do this:

var actualWork = function(param) {
  ...
}

this.publicFunction(param) {
  actualWork(param);
};

this.anotherPublicFunction(param) {
  actualWork(param);
  ...
};

which doesn't seem quite as bad as the other options so far... Are there better approaches?

Community
  • 1
  • 1
MJV
  • 1,782
  • 2
  • 21
  • 33
  • 1
    Why do you call `var ms = this;` (which is written more often as `var self = this;`) "a dirty hack"? – Mikhail Batcer Jun 22 '15 at 09:05
  • It's just a matter of personal taste and stems from my background (especially in Java). Using a new "pointer" to another variable `this` in the same scope just feels weird... But `this` is a special reference and JavaScript has this kind of lexical closure, so it's one of those things I should probably just accept and embrace when writing JS code. When in Rome etc. – MJV Jun 23 '15 at 11:20

11 Answers11

40

I think the best way is to go like this:

var myFunctions = 
{

    myFunc1: function(param) {

    },

    myFunc2: function(param) {
       return foo + myFunctions.myFunc1(param)// do some stuff with the first function        
    }

}
return myFunctions;

because I think if you use this, it may get conflict with the scope where you use the service.

Aladdin Mhemed
  • 3,817
  • 9
  • 41
  • 56
33

I ran into this problem within my own angular coding and opted to use this form of the solution:

angular.module('myService').service('myService', function() {
  var myService = this;
  myService.publicFunction(param) {
    ...
  };

  myService.anotherPublicFunction(param) {
    myService.publicFunction(param);
    ...
  };
});

I preferred this approach because in my code I use publicFunction and inside of anotherPublicFunction I loop over several params that need to call publicFunction as part of the process.

John Braxler
  • 829
  • 9
  • 9
8

Sounds good but what do you do when this is no longer = the service ?

This is the case in the following example:

return {

        myFunc1: function(param) {

        },

        myFunc2: function(param) {

            scope.$watchCollection(param,function(v) {

              return foo + this.myFunc1(param)// do some stuff with the first function 

            }       
        }

}

Because of function(v) { you are now in another function within the function and this is no longer the service but the window.

adolfosrs
  • 9,286
  • 5
  • 39
  • 67
Sleenee
  • 594
  • 1
  • 8
  • 21
4

You can just return an object from within your service like

return {

    myFunc1: function(param) {

    },

    myFunc2: function(param) {
       return foo + this.myFunc1(param)// do some stuff with the first function        
    }

}

So you access it from the outside with service.myFunc1 and from inside its internal functions with this.

angulord
  • 453
  • 1
  • 4
  • 7
  • Thank you for this. As I tried this out in my code, and then in a Plunker, I realized the original problem was only a side effect of something else. It seems my "problematic" code actually works in the way I've presented it in my question. – MJV Nov 08 '13 at 12:20
4

You can set 'this' as variable

angular.module('myService').service('myService', function() {
  var that = this;
  this.publicFunction(param) {
    ...
  };

  this.anotherPublicFunction(param) {
    that.publicFunction(param);
  };
});
1

Well, just create two more pointers/function variables for your service functions with local variables in service and use those to call the service functions from within same service :

*

angular.module('myService').service('myService', function() {
  **var ref1, ref2;**
  this.publicFunction = **ref1** = function(param) {
    ...
  };
  this.anotherPublicFunction = **ref2** = function(param) {
    // how to call publicFunction(param)?
    **ref1(argument);**
    ...
  };
});
0

this is how I implemented:

.service('testSvc', function () {
return {
    f1: function (v1) {
        alert('f1 > v1=' + v1);
    },
    f2: function (v2) {
        alert('f2 > v2=' + v2);
        this.f1('az'); //use 'this'
    }
}

})

Azmeer
  • 734
  • 6
  • 15
0

Below solution worked for me:-

 angular.module('myService').service('myService', function() {

    var self= {
        this.publicFunction(param) {
 ...
 };

 this.anotherPublicFunction(param) {
 // You can call the publicfunction like below
 self.publicFunction(param);
 ...
 };
 return self;

 }
 ]);`
PratikT
  • 35
  • 8
0
angular.module('myService').service('myService', function() {
    return {
      myFunc2: function(param) {
        return foo + myFunc1(param);
      }
    };
    function myFunc1(param){
        ...
    };
});
vijay
  • 846
  • 9
  • 11
-1

Best and easiest way to call is:

myapp.service("SomeService", function ($http) {

    this.func1 = function (params) {
        // Some thing the service returns
        return something;
    }

    this.func2 = function (params) {
        // Some thing the service returns
        var resp = this.func1(params);
        return something;
    }
}
noufalcep
  • 3,446
  • 15
  • 33
  • 51
Riza
  • 1
-1

If you want to use the factory declaration instead of service, you can:-

angular.module('myService').factory('myService', function() {
  var myService = {};
  myService.publicFunction = function(param) {
    ...
  };

  myService.anotherPublicFunction = function(param) {
    // call publicFunction(param) like so
    myService.publicFunction(param);
  };

  return myService;
});    
Kunal
  • 490
  • 2
  • 9
  • 18