AngularJS: Use The Service, Not The Controller

  • January 14th, 2016

If you’re just getting started with AngularJS, you may be stuffing your controllers with lots of business logic. You may even be wondering how to persist data in your controller, and how to pass that data between controllers.

Well, one of the principles of AngularJS is that controllers shouldn’t try to do too much. They are meant to be thin, and “should contain only the business logic needed for a single view” (AngularJS docs).

So where do we put our business logic, and what do we use to persist data across our application? No, NOT $rootScope. The one right answer is Angular services.

An Angular service is a singleton, and is “lazily” instantiated. What “lazily” means is the service is only instantiated when an application component (like a controller) depends on it. And since a service is a singleton, it is only instantiated one time. This makes it suitable for passing data across controllers, or even to other services. This also makes them reusable, testable, and overall much more manageable.

Services come in three different flavors – factory, service, and provider. I will be following this up with another post about the differences, but for let’s not worry about that too much.

Right now we will be focusing on the most common, the factory, which will get us off and running. Let’s take a look at an example:


var myApp = angular.module('myApp',[]);

// Our service:
myApp.factory('messageService', function() {
  
  var message = {}; // Our message object which will be returned
  var privateMsgs = []; // We can use "private" variables (or methods) outside of the message object

  message.addMessage = function(message){
    privateMsgs.push(
    	{id: privateMsgs.length, text: message}
    );
  };

  message.getList = function() {
    return privateMsgs;
  };

  return message;
});

As you can see, a factory looks a bit like a regular JavaScript Singleton without the IIFE (Immediately Invoked Function Expression). And there is also no need to return a public method to get an instance. Like I mentioned above, the Angular service isn’t instantiated until needed – and these components are abstracted away by Angular, so all you need to do is return the object you’d like to be using at some point. Note that we also have a private variable outside of service object that can still be used by it.

Now, let’s take a look at a controller:


function MessageController($scope, messageService) {
  $scope.messages = messageService.getList();
    
  $scope.addMessage = function() {
    messageService.addMessage($scope.newMsg);
    $scope.newMsg = null;
  };
}

We have a thin controller – with two dependencies injected, $scope and our newly created messageService. Now, our data is persisting in a private variable within our service, not our controller. We also have a place to put reusable business logic as we build up our messaging application.

Finally, let’s add a little bit of markup and see it in action using JSFiddle. In this fiddle, I’ve added an additional controller so you can see the data shared between controllers.

That should get you off and running. Questions, comments, feedback? Leave it all below. Thank you!

Tags: , , , , , ,

One response to “AngularJS: Use The Service, Not The Controller”

  1. […] AngularJS: Use The Service, Not The Controller […]

Leave a Reply