Recommended way to write an AngularJS provider?

83 views
Skip to first unread message

modern...@gmail.com

unread,
Jan 7, 2015, 5:25:32 PM1/7/15
to closure-comp...@googlegroups.com
What is the recommended way to write an AngularJS provider for apps that use Closure?

In the AngularJS Style Guide, there is an example of how to write a service but what about a provider? The example given for a service is as follows:

/**
 * @param {!angular.$http} $http The Angular http service.
 * @constructor
 */

hello
.request.Request = function($http) {
 
/** @type {!angular.$http} */
 
this.http_ = $http;
};


hello
.request.Request.prototype.get = function() {/*...*/};

Any help would be appreciated.

Thanks,
Brian

Eric Lemoine

unread,
Jan 8, 2015, 2:43:53 AM1/8/15
to closure-comp...@googlegroups.com

I've been wondering about the same.

It seems to me that a type is missing for that in the angular-1.3.js externs file.

There should be a @typedef looking like this:

/**
  * @typedef {{$get: (Function|Array.<(string|Function)>)}}
  */
angular.ServiceProvider;

With this we'd be able to declare a service provider like this:

/**
  * @return {angular.ServiceProvider}
  */
app.createMyServiceProvider = function() {
  return {
    $get: function() {
      // ...
      return myService;
    }
  };
};

module.provider('myService', app.createMyServiceProvider);

Does it make any sense?

modern...@gmail.com

unread,
Jan 8, 2015, 10:52:38 AM1/8/15
to closure-comp...@googlegroups.com
I agree. The externs should be updated.

In your example, how would you go about declaring a type for the actual service? Meaning, if I wanted to namespace the service definition (ie. app.MyService), what would that look like? I was originally thinking of doing something like this:

goog.provide('app.MyService');
goog
.provide('app.MyServiceProvider');


/**
 * MyServiceProvider
 * @constructor
 * @export
 */

app
.MyServiceProvider = function() {


   
/** @type {string} */
   
var defaultPath = "/foo";

   
/**
     * MyService definition
     * @param {!angular.$http} $http The Angular HTTP Service.
     * @constructor
     * @ngInject
     */

    app
.MyService = function($http) {
       
this.http_ = $http;
   
};


   
/**
     * Do Something
     * @return {!angular.$q.Promise} Promise containing the response.
     * @export
     */

    app
.MyService.prototype.doSomething = function() {
       
return this.http_.get(defaultPath);
   
};


   
/**
     * Sets the default path
     * @param {string} path The default path.
     * @export
     */

   
this.setDefaultPath = function(path) {
        defaultPath
= path;
   
};


   
/**
     * Returns an instance of MyService
     * @return {!app.MyService}
     * @export
     */

   
this.$get = app.MyService;
};


But that seems a little crazy.

- Brian

Eric Lemoine

unread,
Jan 8, 2015, 3:24:45 PM1/8/15
to closure-comp...@googlegroups.com

Using @export for $get may be a good idea, and we may actually not need a new extern declaration at all!

How about the following?

goog.provide('app.MyService');
goog.provide('app.MyServiceProvider');

/**
  * @constructor
  * @export
  */
app.MyService = function() {
  // ...
};

/**
  */
app.MyService.prototype.doSmthg() {
  // ..
};

/**


  * @constructor
  * @export
  */
app.MyServiceProvider = function() {

  // ...
};

/**
  * @export
  * @ngInject
  */
app.MyServiceProvider.prototype.$get = function($http) {
  var service = new app.MyService();
  // ...
  return service;
};

module.provider('MyService', function() {
  return new app.MyServiceProvider();
});

This is untested.

modern...@gmail.com

unread,
Jan 8, 2015, 4:35:01 PM1/8/15
to closure-comp...@googlegroups.com
The problem with this approach is that the service definition is outside of the provider closure, which prevents you from reaching local variables.
Reply all
Reply to author
Forward
0 new messages