Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript AngularJS Basics (1.x) Services in Angular What are services?

jason chan
jason chan
31,009 Points

What's happening here in the app? Angularjs

angular.module("todoListApp", [])
.controller('mainCtrl', function($scope, dataService){

// This line below
  $scope.helloConsole = dataService.helloConsole;

    $scope.learningNgChange = function () {
        console.log("Input changed!");
    };

  $scope.todos = [
    {"name": "Do Something"},
    {"name": "Do Nothing"},
    {"name": "Do bogus shit"},
    {"name": "Do more shit"},
    {"name": "Do stuff"},
    {"name": "Do nothing"},
  ]

})
.service('dataService', function(){

    this.helloConsole = function() {
      console.log('This is hello console service!');
    }
    });

I don't understand this line of code. Help.

// This line below
  $scope.helloConsole = dataService.helloConsole;

3 Answers

This creates a service called dataService:

service('dataService', function(){
    this.helloConsole = function() {
        console.log('This is hello console service!');
    };
});

It's basically just an object that has a method helloConsole attached to it.

When creating the controller, you injected the dataService service into it:

controller('mainCtrl', function($scope, dataService)

And this:

$scope.helloConsole = dataService.helloConsole;

...is putting the dataService method helloConsole on your controller's scope.

If you were to call $scope.helloConsole() now, you would see "This is hello console service!" logged, because that's how that method is defined in the dataService service.

Hope this helps. Cheers.

Hey Jason... here is what is going on :)

Services and Factories are used to share functionality within an AngularJS Application.

 $scope.helloConsole = dataService.helloConsole;

// This is saying, I want my variable in this controller to be equal to dataService's helloConsole Function

What you are seeing is re-usable code at its finest :)

David Hughes
David Hughes
5,063 Points

Great explanation!

What are the differences in services and factories?

Anthony c
Anthony c
20,907 Points

So, when we have multiple controllers who are using the same functionality, we can use a service so that we don't have to re-write the functionality over and over in each controller, and can instead just insert the service in each controller. This is shorter, and allows us to use that functionality still.

Is that the basic idea?

jason chan
jason chan
31,009 Points

so it's like caching.

so it's like caching.

Not really. It's really just a way to write modular code that can be used across your application and written only once.

Let's say that you did want to implement some sort of cache, though. Imagine adding 2 to a number was a really expensive calculation that took a long time. You could write a method in a controller that added 2, like this:

myApp.controller('FrontPageController', function() {
    this.addTwo = function(n) {
        return n + 2;
    };
});

Rather than just computing that every time you call addTwo, you could cache the results each time the function is called, so that if you're ever adding 2 to the same value of n you can get instant results. Here's what that could look like:

var addTwoResults = {};

this.addTwo = function(n) {
    if (angular.isUndefined(addTwoResults[n])) {
        addTwoResults[n] = n + 2;
    }
    return addTwoResults[n];
};

That's the basic premise of caching.

Now imagine that you need to add 2 in a different part of the application. But you know that you're going to want to cache the results (remember... we're pretending adding 2 is an expensive, time-consuming calculation). But you don't want to have two copies of that function, because if you ever needed to change the behavior of addTwo you'd have to do it in 2 places (this is the DRY Principle).

This is where services come into play.

Let's add a myComputations service to the app, with our addTwo functionality contained in the service:

myApp.service('myComputations', function() {
    var addTwoResults = {};

    this.addTwo = function(n) {
        if (angular.isUndefined(addTwoResults[n])) {
            console.log('computing addTwo(' + n + ')');
            addTwoResults[n] = n + 2;
        }
        return addTwoResults[n];
    };
});

Now we can inject the myComputations service into the controller(s) in our app:

myApp.controller('myController', function(myComputations) {
    console.log('controller asking for result of 42+2');
    myComputations.addTwo(42); // should see "computing addTwo(42)" in console
    console.log('controller asking again');
    myComputations.addTwo(42); // should not see anything in console this time
});

This functionality can now be shared across the app, and the code is only written once!


Just for fun, here's a version of the myComputations service where addTwo takes 3 seconds to compute...

myApp.service('myComputations', function($q, $timeout) {
    var addTwoResults = {};
    // this holds promises (read about them [here](https://docs.angularjs.org/api/ng/service/$q))
    var addTwoPromises = {};

    var computeAddTwo = function(n) {
        // prevent the same computation from getting done more than once if
        // if it's called a second time before the first time returns the result
        if (angular.isDefined(addTwoPromises[n])) {
            return addTwoPromises[n];
        }

        // first define a deferred, which will give us a promise
        var deferred = $q.defer();
        addTwoPromises[n] = deferred.promise;
        // now resolve the deferred after 3 seconds
        $timeout(function() {
            deferred.resolve(n + 2);
        }, 3000);
        // return a promise, which can be viewed by the caller to get the result
        return addTwoPromises[n];
    };

    this.addTwo = function(n) {
        if (angular.isUndefined(addTwoResults[n])) {
            console.log('computing addTwo(' + n + ')');
            addTwoResults[n] = computeAddTwo(n);
        }
        return addTwoResults[n];
    };
});

myApp.controller('myController', function(myComputations) {
    console.log('controller asking for result of 42+2');
    // we now need to use `then` to get the result, since this is now an asynchronous function call
    myComputations.addTwo(42).then(function(result) {
         // should see "computing addTwo(42)" in console
        console.log('result', result);

        console.log('controller asking again');
        myComputations.addTwo(42).then(function(result) {
            // should not see "computing addTwo(42)" in console this time
            // also, it should print the result instantly (instead of after 3 more seconds)
            console.log('result', result);
        });
    });
});

I wrote this in plunkr if you want to see it work.

Sorry for the essay response, just got bored and rambled!