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.