Shadman Kudchikar

AngularJS Service

AngularJS Service

Contents

What are Services in Angularjs?

Angularjs Services are functions or objects that contains reusable code that can get consumed accross app by controllers, directives, filters and other services using Dependency Injection Mechanism of Angularjs.

These are also called as singletons, which are the objects that are instantiated only once per application.

Services provide a method for us to keep data around the lifetime of the app and communicate across controllers in a consistent manner.

Why use Services in Angularjs?

Writing your own services is a great way to implement reusable code and they’re the perfect place to capture the logic specific to your application.

Following are its uses:

Real World Example

The most simple example I could come up with is alert service or notifier service, consider you are using routing and ng view in your angular app and you want to send classic bootstrap alert box in your main index controller outside of your route controller, than creating a alert service that get consumed by both controller can solve this problem.

Below is the sample code.

angular.module('app')
    .factory('alertService', function ($interval) {

        return  {
            alerts: [], 

            addAlert: function addAlert(icon,type, title, message, timeout) {
                var alert = {
                    icon: icon,
                    type: type,
                    title: title,
                    message: message
                };
                this.alerts.push(alert);

                var serv = this;

                $interval(function () {
                    var alertIndex = serv.alerts.findIndex(function (a) { return a == alert });
                    if (alertIndex > -1) {
                        serv.alerts.splice(alertIndex, 1);
                    }                    
                }, timeout, 1);
            },

            addDanger: function addDanger(title, message, timeout = 3000) {
                this.addAlert("fa-ban","alert-danger", title, message, timeout);
            },
            addWarning: function addWarning(title, message, timeout = 3000) {
                this.addAlert("fa-warning","alert-warning", title, message, timeout);
            },
            addInfo: function addInfo(title, message, timeout = 3000) {
                this.addAlert("fa-info","alert-info", title, message, timeout);
            },
            addSuccess: function addSuccess(title, message, timeout = 3000) {
                this.addAlert("fa-check", "alert-success", title, message, timeout);
            },
        }

    });

Different Methods To Create AngularJS Services

There are five functions you can use to create an Angular service. All of these functions may be called on the built-in provide service. All of them are also exposed on the module object as a convenience.

Traditional Provider Method

The most fundamental service creation function is the provider function. Creating services with it allows you to create a configurable provider object. The provider knows how to create the resulting service.

The basic process is that the $provide service creates a provider which contains a function that is used to create a service.

The first function on the $provide service we’ll look at is the provider function. It’s the most fundamental way to create a service. All of the other methods of creating services(factory, service, and value method) which we’ll learn are just wrappers around the provider function (except constant method).

To use the provider function directly, you simply call the function and pass it a name and a function that will define the underlying provider.

The provider created for each service, will be given a name that is the name you specify for the service with the word provider appended to it. So in the below example, the name of the service we will inject into our other components, will be ‘oauth’, and the name of the provider we will inject in module config method will be oauthProvider to configure our oauth service.

Provider function requires service name as first parameter and second parameter it require is the function which must contain a property named $get.

The return value of the function assigned to $get property will represent our service that gets injected.

The benefit of using provider method is that it is configurable which at the end decides the resulting service. None of the other service creation functions allow you to do this.

Let’s see how to create and configure a service with the provider function in code below.

In the below example I created an oauth service that can be used for login and logut operation in the app. It internally depends on custom currentUser and formEncode service and angular built-in $http service. You can find currentUser and formEncode service code here and here.

angular.module("app")
    .config(function ($provide) {
        $provide.provider("oauth", function () {

            var url = "/token";

            this.setUrl = function (newUrl) {
                url = newUrl;
            };

            this.$get = function ($http, formEncode, currentUser) {

                var processToken = function (username) {
                    return function (response) {
                        currentUser.profile.username = username;
                        currentUser.profile.token = response.data.access_token;
                        currentUser.save();

                        $http.get(`api/IdentityEmployee/${username}`).then(function (res) {
                            currentUser.profile.userInfo = res.data;
                            currentUser.save();
                        });

                        return username;
                    }
                };

                var login = function (username, password) {

                    var configuration = {
                        headers: {
                            "Content-Type": "application/x-www-form-urlencoded"
                        }
                    };

                    var data = formEncode({
                        username: username,
                        password: password,
                        grant_type: "password"
                    });

                    return $http.post(url, data, configuration).then(processToken(username));
                };

                var logout = function () {
                    currentUser.profile.username = "";
                    currentUser.profile.token = "";
                    currentUser.remove();
                };

                return {
                    login: login,
                    logout: logout
                };
            }
        });
    }); 

angular.module("app").config(["oauthProvider", function(oauthProvider) {
  oauthProvider.setUrl('/another-token-url');
}]);

The below three service creation methods all internally call the provider function. They’re just syntactic sugar that make your code a little simpler if you don’t need to provide all of the data required by the provider function.

The factory function is much easier to use than the above provider method. If you don’t need to configure the provider, like we did in the last example, then use the factory function which is much simpler and readable way to create your services.

In the below example I created a simple localStorage service that internally use browser window local storage to store key value data.

angular.module("app")
    .factory("localStorage", function ($window) {

        var store = $window.localStorage;

        var add = function (key, value) {
            value = angular.toJson(value);
            store.setItem(key, value);
        };

        var get = function (key) {
            var value = store.getItem(key);
            if (value) {
                value = angular.fromJson(value);
            }
            return value;
        };

        var remove = function (key) {
            store.removeItem(key);
        };

        return {
            add: add,
            get: get,
            remove: remove
        };
    });

Flexible Service Method

The next service creation function is Service, which is simply a wrapper around the factory function. When you call the service function, it will internally call the factory function, which will then call the provider function.

The only difference is that the function you passed to the service method will be treated as a constructor function and called with the JavaScript “new” operator. You would use the service method instead of the factory method if you specifically needed your function to be treated as a constructor and called with the “new” operator.

There are several reasons why you may want that behavior. One is if you have defined an inheritance hierarchy in your code. Creating an instance with “new” will make sure that your instantiated object properly inherits from its prototypes. Here is an example,

 angular.module('app')
        .service('logger', CustomerLogger);

    function LoggerBase() { }

    LoggerBase.prototype.output = function(message) {
        console.log('LoggerBase: ' + message);
    };

    function CustomerLogger() {

        LoggerBase.call(this);

        this.logApp = function(customer) {
            console.log('Customer: ' + customer);
        }
    }

    CustomerLogger.prototype = Object.create(LoggerBase.prototype);

From the above code you can call logger service output method which is part of base LoggerBase class even though logger service is registering CustomerLogger class.

Simple Value Method

Similarly, the value function is just a thin wrapper around the factory function. The value function is just shorthand for calling the factory function with no parameters. If you don’t need to inject anything into your factory function, you can use the value function instead.

angular.module('app').value('clientId', 'a12345654321x');

angular.module('app').controller('DemoController', ['clientId', function DemoController(clientId) {
  this.clientId = clientId;
}]);

You use it in much the same way you use the constant service which is the fifth function available for service creation.

Rare Constant Method

The constant function is totally different from other services. It allows you to register an object literal function or some other constant value with the injector, but it doesn’t call the service, factory or provider methods behind the scenes. What makes it different from value service is that a value service can’t be injected into a module configuration function, but a constant service can.

AngularJS splits the life-cycle into configuration phase and run phase and you can provide configuration to your application via the config function. Since the config function runs in the configuration phase when no services are available, it doesn’t have access even to simple value service objects created via the Value function method.

This is what the Constant service is for.

angular.module('app').constant('tokerUrl', '/another-token-url');

angular.module("app").config(["oauthProvider", "tokerUrl", function(oauthProvider, tokerUrl) {
  oauthProvider.setUrl(tokerUrl);
}]);

Conclusion

There are five methods to create services: Value, Factory, Service, Provider and Constant.

Factory and Service are the most commonly used method. The only difference between them is that the Service method works better for objects that need inheritance hierarchy, while the Factory can produce JavaScript primitives and functions.

The Provider function is the core method and all the other ones are just syntactic sugar on it. You need it only if you are building a reusable piece of code that needs global configuration.

Features / Methods Factory Service Value Constant Provider
can have dependencies yes yes no no yes
uses type friendly injection no yes yes* yes* no
object available in config phase no no no yes yes**
can create functions yes yes yes yes yes
can create primitives yes no yes yes yes

* at the cost of eager initialization by using new operator directly

** the service object is not available during the config phase, but the provider instance is (see the oauthProvider example above).

References


comments powered by Disqus