Service Inheritance in AngularJS using ES6

One of the things that I’ve found is that my Angular services tend to have a lot of duplicate logic in them. The biggest culprit is HTTP calls for CRUD operations. Whether I’m using Restangular, ngResource, or plain ole’ $http, this has been a constant source of un-DRYing in my code. Let’s take a look at using ECMAScript 6’s class and extends to clean up this duplicate code.

We’ll first create a Base class, and put all our shared HTTP calls in there:

class ServiceBase {
  constructor ($http) {
    'ngInject';
    this.$http = $http;
    this.resource = "";
  }

  all() {
    return this.$http.get('api/' + this.resource);
  }
}

export default ServiceBase;

Then, we’ll make our individual services, and set them as subclasses that inherit from our Base class, using the new extends feature. In this example, we’ll create a service that represent ideas.

import ServiceBase from '../base.service';

class IdeaService extends ServiceBase {
  constructor ($http) {
    'ngInject';

    super($http);
    this.resource = "ideas";
  }

  ideaSpecificThing() {
    // does stuff that the base service can't do
  }
}

export default IdeaService;

That’s pretty much the gist of it. If you’d like to see an example implementation, complete with routes and a controller, read on.

The next step is to create a routes file where we will resolve the HTTP query:

function routerConfig ($stateProvider, $urlRouterProvider) {
  'ngInject';
  $stateProvider
    .state('ideas', {
      url: '/ideas',
      templateUrl: 'app/ideas/index.html',
      controller: 'IdeaController',
      controllerAs: 'ideaCtrl',
      resolve: {
        ideas(Idea) {
          return Idea.all();
        }
      }
    });

  $urlRouterProvider.otherwise('/');
}

export default routerConfig;

And then we inject our ideas into our controller:

class IdeaController {
  constructor (ideas) {
    'ngInject';

    this.ideas = ideas;
  }
}

export default IdeaController;

And lastly, we import all our class files and load them into our Angular module as services and a controller:

import ServiceBase from '../app/base.service';
import IdeaService from '../app/ideas/idea.service';
import IdeaController from '../app/ideas/idea.controller';

angular.module('ideaLogger', ['ui.router'])
  .service('ServiceBase', ServiceBase)
  .service('Idea', IdeaService)
  .controller('IdeaController', IdeaController)

That’s all folks! Got any ideas of ways I could make it better? I’d love to hear ’em.

Back