How to convert an angular $resource factory (not service) to ES6

Problem

I'd like to start preparing for Angular 2 by converting existing code over to ES6 (as recommended in this video).

However, I'm immediately stumped, or perhaps unsure about how to proceed. In the video they show a conversion of a service. In my code I'm trying to convert a factory, which is similar but actually quite different when trying to convert to ES6. The service easily follows the class instantiation method, but factories need to return the injected object.

My code started like this:

melange.factory('SomeService', ['$resource', function ($resource) {
  var someResource = $resource('/api/endpoint');

  someResource.customQuery = function() {
    // ... do some custom stuff
  };

  return someResource;
}]);

My First Failed Attempt - So I immediately started to convert over to ES6 and came up with this:

// notice I changed this to service instead of factory
melange.service('SomeService', ['$resource', SomeService]);

class SomeService {
  constructor ($resource) {
    var someResource = $resource('/api/endpoint');

    someResource.customQuery = function() {
      // ... do some custom stuff
    };

    return someResource;
  }
}

But that's not right... the constructor is returning a resource.


Maybe Success Attempt - So it's really the Resource (or really a Route object) that is the thing I want to 'class-ify'. But since a Resource object has a specific interface already of methods, I'll need my class to extend the base Resource object. But that is generated dynamically by calling the $resource factory function. So I came up with this maybe correct code:

melange.service('SomeService', ['$resource', SomeResource]);
var $resource = angular.injector().get('$resource');

class SomeResource extend $resource('/api/endpoint') {
  customQuery() {
    // ... do some custom stuff
  }
}

So I have to get $resource from the injector before declaring my class. I'm just not sure if extending $resource('/api/endpoint') is even valid ES6. It seems to work generally during babel transpile though.


Am I doing this right?

Problem courtesy of: nfiniteloop

Solution

You can't use ES6 classes as easily with factories, so I would advise making everything a service.

angular.module('test', [])
.service('SomeService', ['$resource', class SomeService {
  constructor($resource) {
    this.resource = $resource('/api/something');
  }
  customQuery() {
    return doSomething(this.resource);
  }
}]);

Here's how it looks when it's transpiled: http://goo.gl/8Q4c8b

Here's a working plunkr with the transpiled code inside: http://plnkr.co/edit/RS48OerLYQCERPYzbuuM?p=preview

Solution courtesy of: Andrew Joslin

Discussion

Just faced the same issue. And understood that there's no need in dealing with class here (please correct me if i'm wrong), as usually $resource factory is used just to return itself. So consider this option below:

export default angular.module('service.smth', [])
  .service('SomeService', $resource => $resource('/api/something', {}, {
    customQuery: { ... }
  }))
  .name;
Discussion courtesy of: Egor Litvinchuk

This recipe can be found in it's original form on Stack Over Flow.