The Provider

Use a provider if you need to configure a service before it runs. This is the only reason you’d ever use a provider, because they are the most complex of the three to use. For example, it’s common to want to use $httpProvider to set up default headers before the $http service is instantiated.


But what mainly brings us here is the fact that you cannot do this:

 some_module.service('SomeService', function() {
    this.someMethod = function() { ... };
});

some_module.config(function(SomeService) {
    // do something with SomeService
});

SomeService has not yet been instantiated and it simply doesn’t exist. But you CAN do this:

 function SomeProvider() {
    // some setup code goes here
    this.last_name = 'Hiller';

    // required method $get; acts as factory or service
    this.$get = function() {
        var that = this;
        return {
            someMethod: function() { return that.first_name + ' ' + that.last_name }
        };
    };
}

some_module.provider('SomeProvider', SomeProvider) 

// YES, it tacks "Provider" on to the end of any provider you create.
some_module.config(function(SomeProviderProvider) {
    SomeProviderProvider.first_name = 'Chris';
});

// run() just runs arbitrary code immediately after bootstrapping
some_module.run(function(SomeProvider) {
    SomeProvider.someMethod(); // returns 'Chris'
});

And some unit tests showing this works:

 describe('SomeProvider', function () {
    it('should be injectable', inject(function (SomeProvider) {
        expect(SomeProvider).not.toBeUndefined();
    }));
    it('should return configured name from someMethod', inject(function (SomeProvider) {
        expect(SomeProvider.someMethod()).toBe('Chris Hiller');
    }));
    it('should provide a provider', function () {
        module(function (SomeProviderProvider) {
            expect(SomeProviderProvider.last_name).toBe('Hiller');
        });
    });
});