2

just wondering if anyone had any patterns / approaches to doing "object oriented" services in angular. By this I mean a service that basically creates a class that creates "instances" of itself:

function MyService(injectedServiceA, injectedServiceB) {
  return function MyService(arg1, arg2 ... ) {
     var var1 = arg1;

     this.someFunction() {
        ... do something with var1 ...
     }
  }
}

and injected:

angular.module('MyModule', []).service('MyService', MyService);

and this service could then be provided to a controller and the controller could then create an instance of it:

$scope.myService = new MyService(arg1, arg2 ... );

and the view uses someFunction.

I took this (naive?) approach which did not work:

class MyService {
  {
    constructor(arg1, arg2 ... ) {
      this._var1 = arg1;
    }

    someFunction() {
        ... do something with this._var1 ...
    }
  }
}

class MyServiceMaker {
  constructor(injectedServiceA, injectedServiceB);
  make(arg1, arg2 ... ) { return new MyService(arg1, arg2 ...); }
}

and injected:

angular.module('MyModule', []).service('MyServiceMaker', MyServiceMaker);

and then in controller:

 $scope.myService = MyServiceMaker.make(arg1, arg2 ... );

this constructed totally fine, etc. But when my someFunction is called on myService, the this was undefined.

11
  • Can you show more code on which line throws error? I am assuming it is someFunc how are you invoking someFunc? You cannot copy the reference of myService.someFunc and call it from the view. Commented Oct 22, 2015 at 19:23
  • ah sorry i added that part of the code. also, agree, definately pretty terrible that I am instantiating this myself ... although, not sure how else to do it? Even in the es5 version I was instantiating it myself (just using the new syntax instead of my own stupid maker class) Commented Oct 22, 2015 at 19:23
  • What about factories?? Commented Oct 22, 2015 at 19:24
  • You could just register via angular service and inject it right? You may want to read about what this means. How you are defining the class looks fine, your issue may be how you are using it. Commented Oct 22, 2015 at 19:24
  • Why should the service create instances of its own class, rather than instances of another class. It would make things much less confusing, and you wouldn't lose anything. That's what you're doing in your second example, and it should work fine. If it causes a problem, then post the real code and explain what the problem is. Commented Oct 22, 2015 at 19:26

2 Answers 2

1

There is zero reason to create MyServiceMaker as a class. The outer function MyService in your orginal example never was a class, and it should not be.

Just go for

angular.module('MyModule', []).service('MyService', makeMyService);
function makeMyService(injectedServiceA, injectedServiceB) {
  return class MyService {
    constructor(arg1, arg2 ... ) {
      var var1 = arg1;
      this.someFunction = function() {
        …
      }
    }
    … // further prototype methods
  }
}

or if you want use more ES6 features, you could go for an arrow function instead of declaring makeMyService:

angular.module('MyModule', []).service('MyService', (injectedServiceA, injectedServiceB) =>
  class MyService {
    constructor(arg1, arg2 ... ) {
      this._var1 = arg1;
    }
    someFunction() {
      …
    }
  }
);
Sign up to request clarification or add additional context in comments.

3 Comments

yea this is much better than having a maker class
although does this force me to define the class inside the anonymous function?
Yes, because you want to use the injected dependencies (parameters) in the class methods, don't you?
0

Theres two main patterns.

Using a service:

export default class NameService {
  constructor($q) {
    this._$q = $q
  }

  getName() {
    return this._$q.when("Bobby Tables")
  }
}


angular.module('myApp', [])
  .service('NameService', ['$q', NameService])

Using a factory:

export default class NameFactory {
  constructor($q) {
    this._$q = $q
  }

  getName() {
    return this._$q.when("Bobby Tables")
  }
}



angular.module('myApp', [])
  .factory('NameService', ['$q', ($q) => new NameService($q)])

Here's a great article discussing services in Angular 1.x with ES6: http://www.michaelbromley.co.uk/blog/350/exploring-es6-classes-in-angularjs-1-x%20nice

5 Comments

yea i basically tried to follow the instructions in the blog post -- but the problem is creating a service which can create instances of itself which I don't think that addresses
@hiroprotagonist services should be singletons by design. Why do you want to create multiple instances of them?
Why would you want to create a factory, it could just be .service('NameService', NameService) and annotate the deps via static $inject, constructor(private _$q) { etc...
@PSL you can do that. Using a factory over a service offers semantic value about what's returned. As the application's architect its your call.
@agconti factory is not designed for class, that is what service is for. it is used when you are creating an instance youself within a function with a module pattern or so on. Actually in the link you shared itself pete has mentioned it.. :) there is actually no point in trying to hack together a way to register a class via the module.factory() method. Just use module.service() instead.. And to the point OP is doing alright in this regards.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.